面向对象编程(OOP)
面向对象程序设计(Object Oriented Programming)作为一种新方法,其本质是以建立模型体现出来的抽象思维过程和面向对象的方法。模型是用来反映现实世界中事物特征的。任何一个模型都不可能反映客观事物的一切具体特征,只能对事物特征和变化规律的一种抽象,且在它所涉及的范围内更普遍、更集中、更深刻地描述客体的特征。通过建立模型而达到的抽象是人们对客体认识的深化。
原文链接:全网最完整Java学习笔记
概述
面向对象(Object-Oriented,简称 OOP)是一种程序设计的范式,它基于对象的概念,将数据和操作数据的行为封装在对象中,以模拟现实世界的问题和解决方案。 
核心概念:
对象(Object): 对象是现实世界中的实体或概念,在程序中被抽象为具有状态(属性)和行为(方法)的实例。
类(Class): 类是对象的模板,它定义了对象的属性和方法。类是对象的抽象,实际的对象是根据类的定义实例化而来的。
封装(Encapsulation): 封装是将对象的属性和方法封装在一个单元内,对外部隐藏对象的具体实现细节。通过封装,对象的内部实现对外部是不可见的,只有公共接口对外部可见。
继承(Inheritance): 继承允许一个类(子类)继承另一个类(父类)的属性和方法。子类可以继承父类的属性、重写父类的方法,从而减少代码量。
多态(Polymorphism): 多态允许不同对象对同一消息做出响应,提供了灵活性和可扩展性。其实现方式包括方法重载和方法重写。
类和对象
基本介绍
类:现实中一种具有共同属性、行为的事物的抽象。它定义了一组属性(成员变量)和方法(成员方法),用于描述具有相似特征和行为的对象集合。
对象:对象是类的一个实例,是能够看得到摸的着的真实存在的实体。
总结起来就是一句话:类是对象的抽象,对象是类的具体实现。
例如声明一个Person类,有名字和年龄两个属性;然后便可以通过这个类创建两个对象,分别是Alice和Bob,他们的年龄不一样。
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 public class Person {
// 成员变量
String name;
int age;
// 构造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 成员方法
public void work() {
System.out.println(name + " is working.");
}
public void study() {
System.out.println(name + " is studying.");
}
}
public class Test {
public static void main(String[] args) {
// 创建 Person 类的对象
Person person1 = new Person("Alice", 25);
Person person2 = new Person("Bob", 30);
// 调用对象的方法
person1.work();
person2.study();
}
}结果:
 1
2 Alice is working.
Bob is working.
内部类
内部类:在一个类中定义类。
分为:
- 成员内部类(成员位置)
 - 局部内部类(成员方法内)
 - 匿名内部类(方法内)
 
匿名内部类:一个继承了其他类或者实现了其他接口的子类对象。
内部类可以直接访问外部类私有、公有成员。外部类要访问内部类成员要创建对象。
1  | public class Outer {  | 
创建对象的几种方法
概述:
- new:例如Person person1 = new Person();
 - 反射:先获取类的Class对象,通过newInstance()方法创建对象;
 - 对象的clone()方法: 类实现Cloneable 接口,重写 clone()方法, 编写浅拷贝或者深拷贝的逻辑。然后调用对象的clone()方法就可以克隆出对象。
 - 反序列化:反序列化对象时,JVM会创建一个单独的对象。需要让类实现Serializable接口,通过ObjectInputStream类的readObject()方法从磁盘中反序列化对象。反序列化创建对象是深拷贝。
 
1  | // 1.使用 new 关键字: 这是最常见的创建对象的方式,使用 new 关键字直接调用类的构造方法  | 
方法
基本介绍
方法(Method):一组执行特定任务的代码块。它可以在类中定义一次,然后在本方法、其他方法中被多次调用。
作用:提高代码的可读性和可维护性。
例如小明要吃多顿饭,每顿饭吃的食物不同,可以将“吃饭”这个行为抽象成方法,从而减少代码量:
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 public class Test {
private static String name = "小明";
// 吃饭方法
public static void eat(String food) {
System.out.println("=====");
System.out.println(name + " is eating " + food);
System.out.println("=====");
}
public static void main(String[] args) {
eat("西瓜");
eat("白菜");
eat("可乐");
eat("番茄");
}
}
基本用法
在 Java 中,方法的定义包括以下几个要素:
- 修饰符: 方法可以有访问修饰符,例如 public、private、protected 或默认(包内可见)。
 - 返回类型: 方法可以返回一个值,指定返回值的数据类型,如果方法不返回任何值,可以使用 void。
 - 方法名: 方法名是方法的标识符,用于在程序中调用方法。
 - 参数列表: 方法可以接受零个或多个参数,参数用于向方法传递数据。
 - 方法体: 方法体包含实际执行的代码块,实现方法的功能。
 
1  | // 方法的定义  | 
方法的重载
重载(Overload)
重载(Overload):指一个类中可以有多个方法具有相同的方法名,但这些方法的参数类型不同、个数不同、顺序不同。
注意:方法返回值和访问修饰符可以不同。
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 public class hello {
public static void main(String args[]) {
f();
}
public static void f() {
System.out.println("3f");
}
public static void f(int a) { // 重载,注意返回值同,参数不同
System.out.println(a);
}
// 下面两个注释的方法就不是重载,会报错
// public static int f(){ //返回值不同
// System.out.println("hello");
// }
// void f(){ // 修饰符不同
// return 666;
// }
}示例:求和的数学类:
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 public class MathOperations {
// 求和方法,接受两个整数参数
public int sum(int num1, int num2) {
return num1 + num2;
}
// 重载的求和方法,接受三个整数参数
public int sum(int num1, int num2, int num3) {
return num1 + num2 + num3;
}
// 重载的求和方法,接受两个双精度浮点数参数
public double sum(double num1, double num2) {
return num1 + num2;
}
public static void main(String[] args) {
// 创建 MathOperations 对象
MathOperations math = new MathOperations();
// 使用不同的方法进行求和
int result1 = math.sum(5, 10);
int result2 = math.sum(3, 7, 12);
double result3 = math.sum(2.5, 3.5);
// 打印结果
System.out.println("Sum of two integers: " + result1);
System.out.println("Sum of three integers: " + result2);
System.out.println("Sum of two doubles: " + result3);
}
}
重载和重写的区别
重载:方法名相同且参数列表。重载要求发生在同一个类中,多个方法之间方法名相同且参数列表不同。重载与返回类型和访问修饰符无关。方法名相同返回类型不同会直接报错。
重写:方法名、参数列表、返回类型与父类相同。重写发生在父类子类或接口实现类中,若子类方法想要和父类方法构成重写关系,则它的方法名、参数列表、返回类型必须与父类方法相同。
重写时:
- 返回值类可以是原返回值类的子类。例如工厂方法设计模式里,抽象工厂类的
createObject()方法返回值是抽象产品类,具体工厂类的createObject()方法返回值是具体产品类 - 访问权限不能比其父类更为严格
 - 抛出异常不能比父类更广泛
 
注意:构造方法不能重写。
可变参数
Java 5 以后引入了可变参数(Varargs),允许方法接受可变数量的参数。可变参数在方法的参数列表中使用省略号 ... 表示。
1  | // 可变参数的定义  | 
注意:
可变参数必须是方法的最后一个参数。例如void (int a,int… b)正确,而void (int… a,int b)会报错。
一个方法最多只能有一个可变参数。
可变参数在方法内部被当作数组处理。
示例:求和的数学类:
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 public class MathOperations {
// 求和方法(整数数组)
public static int sum(int[] numbers) {
int result = 0;
for (int num : numbers) {
result += num;
}
return result;
}
// 求和方法(可变参数)
public static int sum(int... numbers) {
int result = 0;
for (int num : numbers) {
result += num;
}
return result;
}
// 求和方法(双精度浮点数数组)
public static double sum(double[] numbers) {
double result = 0;
for (double num : numbers) {
result += num;
}
return result;
}
// 求和方法(可变参数)
public static double sum(double... numbers) {
double result = 0;
for (double num : numbers) {
result += num;
}
return result;
}
public static void main(String[] args) {
// 示例:整数求和
int[] intArray = {1, 2, 3, 4, 5};
int intSum = sum(intArray);
System.out.println("Integer Sum: " + intSum);
// 示例:可变参数整数求和
int varArgsIntSum = sum(1, 2, 3, 4, 5);
System.out.println("VarArgs Integer Sum: " + varArgsIntSum);
// 示例:双精度浮点数求和
double[] doubleArray = {1.1, 2.2, 3.3, 4.4, 5.5};
double doubleSum = sum(doubleArray);
System.out.println("Double Sum: " + doubleSum);
// 示例:可变参数双精度浮点数求和
double varArgsDoubleSum = sum(1.1, 2.2, 3.3, 4.4, 5.5);
System.out.println("VarArgs Double Sum: " + varArgsDoubleSum);
}
}
构造方法
构造方法是一种特殊的方法,与类同名,没有返回类型。
每次创建对象时,都会默认执行一次构造方法。
特点:
- 与类同名,没有返回类型;
 - 构造方法在对象创建时执行,用于设置对象的初始状态。
 - 每个类都可以有一个或多个构造方法,但通常至少有一个默认构造方法(无参数)。
 - 默认构造方法:果在类中没有明确定义任何构造方法,Java 会自动为该类提供一个默认的无参数构造方法。这个默认构造方法执行时不进行特定的初始化操作。
 - 重载:和普通方法一样,构造方法也支持重载,即在同一个类中可以定义多个同名但参数列表不同的构造方法。
 
简单的构造方法:
1  | public class Car {  | 
接口和抽象类
概述
- 接口:对行为的抽象,如吃饭类、睡觉类。
 - 抽象类:对事物的抽象,如动物类,小狗类。
 
接口
接口:对行为的抽象,如吃饭类、睡觉类。
接口的特点:
- 接口没有构造方法。
 - 接口中的方法会被隐式的指定为 public abstract方法,不能定义静态方法。
 - 接口中的变量会被隐式的指定为 public static final 变量,不能定义私有成员。因为是final所以也要显式赋初值。
 - 接口和接口多继承,接口和类多实现。
 - 接口的实现类:除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。
 
1  | public interface Phone {  | 
抽象类
抽象类:对事物的抽象,如动物类,小狗类。
抽象类包含抽象方法的类,它不能被实例化,通常用于作为其他类的基类。
特点:抽象类可以包含抽象方法、具体方法、字段和构造方法。
使用场景:
- 建模共性行为: 当多个类具有相同的行为,可以将这些行为提取到一个抽象类中,以便实现代码的重用。
 - 规范子类: 抽象类可以用于规定子类应该实现的一组方法,强制子类提供这些方法的实现。
 
1  | public abstract class Animal {  | 
面对对象三特性
面向对象的三大基本特征是:封装、继承、多态。分别实现了数据的隐藏与保护、代码的复用扩展以及行为的灵活适配。
封装是对数据和行为进行集中管理的过程,其核心在于隐藏内部实现细节,仅通过接口与外界交互。主要作用包括:
- 数据保护:通过访问权限控制,如 private、protected 限制外部直接修改属性;
 - 接口标准化:提供统一的方法调用入口,如 getter、setter 控制属性访问;
 - 模块化设计:将同一类功能封装到同一对象中。
 
继承通过父子类关系实现代码复用和扩展,其特点包括:
- 子类复用父类功能:子类可直接使用父类的公共属性和方法;
 - 层级扩展能力:子类可新增特性或重写父类方法,如子类用 extends 继承父类并添加特有属性;
 - 访问规则约束:父类私有成员(private)不可被子类继承,保证封装性。
 
多态通过统一的接口实现不同类型的差异化行为,具体表现为:
- 动态绑定:父类引用指向子类对象;
 - 方法重写与重载:子类覆写父类方法(重写)或同一类中同名不同参方法(重载);
 - 灵活性增强:同一方法在不同子类中表现不同。
 
封装
封装:通过private修饰符,将类的某些信息隐藏在类的内部,不允许外部程序直接访问。
封装将对象的状态和行为包装在一个类中并对外界隐藏实现的细节,可以通过访问修饰符控制成员的访问权限,让外部程序通过该类提供的方法来实现对内部信息的操作和访问。
示例:将价格、年龄等信息封装到小狗类中,外部不能直接访问,只能通过get和set方法访问。
1  | public class Dog{  | 
优点:安全性和复用性。
- 安全性:通过方法来控制成员变量的操作,提高了代码的安全性
 - 复用性:把代码用方法进行封装,提高了代码的复用性,降低了耦合性。
 
继承
继承:继承是指一个类通过从另一个类继承其属性和方法。这使得子类具有其父类的行为和属性,同时可以扩展或修改这些行为和属性以满足特定的需求。
优点:提高代码复用性,维护性,实现代码共享。
缺点:高耦合性,有侵入性,父类改变子类也会改变。
特点:子类拥有父类非 private 的属性、方法。可以拥有自己的属性和方法,即子类可以对父类进行扩展。可以用自己的方式实现父类的方法。
注意: Java 不支持多继承,但支持多重继承。
子类所有构造方法会默认先运行super();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23public class Animal {
public String name;
int age = 3;
public Animal(String name, int age) {
// 初始化属性值
}
public void show() { // 吃东西方法的具体实现 }
public void sleep() { // 睡觉方法的具体实现 }
}
// 子类
public class Penguin extends Animal{
int age=4;
public Penguin(){
super(); // 不写也会默认运行
}
// 注解重写,检查重写是否正确。例如修饰符(子类重写方法的访问权限要≥父类)、函数名错误。
public void show(){ // 重写父类中show(),如果去掉public会报错。想再用super.show();
int age = 5;
System.out.println(age); // 5,子类可以访问父类非私有成员变量
System.out.println(this.age); // 4
System.out.println(super.age); // 3
}
}使用 implements 关键字可以变相的使java具有多继承的特性
1
2
3
4
5
6
7
8public interface A {
public void eat();
public void sleep();
}
public interface B {
public void show();
}
public class C implements A,B {}
多态
多态:同一行为具有多个不同的表现形式或形态。例如同一个接口,使用不同的实例而执行不同操作。使程序更灵活、易于扩展。
多态最常用的是接口引用指向实现类对象,这样当之后程序需要更新时候,只需要修改new后面的实现类即可,左边就不用修改了,从而降低耦合。
简单一句话,多态是:接口引用指向实现类对象。
在Spring框架中,甚至可以通过配置或注解连实例化的new也不用了,从而更高层次的降低耦合。
1  | List<String> a = new ArrayList<String>();  | 
这样写的话,等号右边换成Vector 或 LinkedList 时,就可以很少修改代码量,降低耦合。
1  | // 向上转型:父类引用指向子类对象。编译看左边(调用子类特有变量、方法会报错),运行看右边(优先运行子类重写后的方法)。  | 





