面向对象
1. 面向对象
- 面向过程:自上向下,将一个大问题分解为几个小问题,再将小问题分解为更小的问题,最后将任务划分成一个一个具体的步骤,分别去执行,最小粒度细化到方法层面
- 面向对象:将程序所有参与角色都看作一个个对象,通过对象和对象之间的相互调用来完成系统的功能,是一种将程序模块化的思想
1.1 类和对象
对象是主体,类是用来创建对象的;类是产生对象的模板,所有的对象都是通过类来创建的
对象的特征:
- 属性,对象的静态特征
- 方法,对象的动态特征
类是对象的抽象化描述,对象是类的具体实例
对象的创建:new、调用类的构造方法:
- 类默认有一个无参构造,手动创建一个有参构造后,该默认构造就会被覆盖
- 使用有参构造创建对象,只需调用一次方法,就可以同时完成创建和赋值;使用无参需要创建、赋值两步操作
1.2 成员变量和局部变量
作用域:就近原则;成员变量和局部变量重名时,采用就近原则进行优先级取值;
成员变量有默认值,局部变量没有:
byte、short、int、long、float、double:0
char:’’
boolean:false
引用类型:null
1.3 三大特征
封装、继承、多态
封装
将类的各种信息(属性/成员变量和方法)封装到内部,使得外部无法直接访问,提高数据安全性。
属性私有化
提供公有方法访问私有属性(set/get),在方法中添加逻辑,控制数据的安全性
外部通过 set/get 方法访问属性
static
static 表示静态或全局,可用来修饰成员变量、成员方法、代码块,被修饰的资源属于整个类,所有对象都可以共享这些资源;
使用 static 修饰后,方法就会独立于该类的任何一个实例对象,不属于任何对象,而是属于类,访问时不需要依赖于任何一个对象,可以直接通过类来访问。
static 修饰的方法(静态方法)不能使用 this 关键字;this 表示当前对象,静态资源属于类,不属于任何对象;同时静态方法也不能访问类的实例变量和实例方法(非 static 修饰的)
static 修饰代码块,静态代码块的特点是只执行一次,当类被加载到内存时执行,不需要手动调用,会自动执行;且也只能访问静态资源;创建对象时,静态代码块的执行先于构造函数的执行,即类加载 –> 创建对象
this
永远指向构造或调用的当前实例;
可用于在构造器里访问另一个构造器,此时只能放在第一行:
1 | |
this() 调用本类构造函数;注意构造函数不能进行递归,会导致无限创建对象,堆内存溢出
super
super() 调用父类构造函数
继承
类之间资源共享的一种方式,一个类中的信息(成员变量、成员方法)可以直接被另外的类拥有。
子类能继承父类的非私有资源(非 private 修饰的资源)
- 创建子类对象之前,会自动创建父类对象
- 无参创建子类对象,默认调用父类的无参构造创建父类对象
- 有参创建子类对象,也默认调用父类的无参构造创建父类对象
父类也叫超类,子类也叫派生类;创建子类时通过有参构造创建父类对象(super):
1 | |
多态
一种事务可以有多种不同的表现形态,一个对象在不同的业务场景中以不同的形式出现,根据不同的业务场景,对象呈现出不同形式。
- 必须有继承关系,只有构建继承关系,才能使一个对象可以进行不同形式形式的变形
- 父类引用指向子类实例
1 | |
1 | |
1 | |
1 | |
1 | |
1.4 方法重载和重写
- 重载:在同一个类中,两个方法的方法名相同,参数列表不同(数据类型、形参个数),与返回值无关
- 重写:子类在继承父类方法的基础上,对父类方法进行重新定义,覆盖父类方法的操作叫做重写;规则:
- 方法名相同
- 参数列表相同
- 子类方法的返回值与父类方法的返回值类型相同或者是其子类(返回值:父类 > 子类)
- 子类方法的访问权限不能小于父类(访问权限:子类 > 父类)但能被子类重写的方法一定是非 private 的
权限修饰符
| 修饰符 | 当前类 | 同 package | 子孙类 | 其他 package |
|---|---|---|---|---|
| public | √ | √ | √ | √ |
| protected | √ | √ | √ | × |
| friendly | √ | √ | × | × |
| private | √ | × | × | × |
1.5 抽象类和抽象方法
抽象方法:只把方法定义出来,但不做实现
抽象类:一个类中一旦出现一个抽象方法,则该类必须定义为抽象类;抽象类中那个可以没有抽象方法,也可以有普通方法
1 | |
2. 面向对象高级部分
2.1 Object 类
Object 是所有 Java 类的共同父类
Java 所有对象有一些共性,如:hashCode() 获取地址,getClass() 获取类信息,……
| 方法 | 描述 |
|---|---|
| toString() | 以字符串的形式返回对象的信息 |
| equals(Object obj) | 判断两个对象是否相等 |
| hashCode() | 返回对象的内存地址 |
equals
Object 类中的 equals 方法:
1 | |
String 类对 equals 方法的重写:
1 | |
自定义类重写的 equals 方法:
1 | |
注:基本数据类型的值直接在栈中存放,所以用 “==” 比较;引用数据类型在栈中存放的是对象在堆中的地址,不能用 “==” 比较,应用 equals() 比较值
hashCode 和 equals 的关联:
都是用来判断两个对象是否相等;hashCode 的效率更高;
hashCode 的值不相等,则两个对象一定不是同一个对象;
hashCode 的值相等,两个对象不一定是同一个对象,不能确实对象的关系;
需要考虑效率的场景下,需要两者配合判断对象是否相等以提高效率,如:
集合框架底层实现,允许/不允许存储重复数据。
**重写 equals() 时必须重写 hashCode()**:
因为两个相等的对象的 hashCode 值必须是相等。也就是说如果 equals 方法判断两个对象是相等的,那这两个对象的 hashCode 值也要相等;
如果重写 equals() 时没有重写 hashCode() 方法的话就可能会导致 equals 方法判断是相等的两个对象,hashCode 值却不相等。、
可变参数
可作为一个数组进行操作,传入任意数量对应类型形参。只能出现一个,且只能放在最后。
2.2 包装类
包装类是 Java 提供的一组类,专门用来创建 8 种基本数据类型对应的对象:
Byte、Short、Integer、Long、Float、Double、Character、Boolean
装箱和拆箱
装箱:将基本类型用它们对应的引用类型包装起来
构造方法、
valueOf()1
2
3
4
5int i = 3;
Integer num = new Integer(i); // 遵循类型自动转换规则(小->大)
Integer num1 = new Integer("3"); // 除Character外,都有转字符串的构造方法
Integer num2 = Integer.valueOf(i); // 第二种装箱方法
...拆箱:将包装类型转换为基本数据类型
*Value()、parse*1
2int num4 = num.intValue(); // 拆箱
int num5 = Integer.parseInt("3"); // 字符串还原为基本数据类型,Character没有
2.3 接口
面向接口编程:将程序的业务逻辑进行分离,以接口的形式去对接不同的业务模块,接口只串联不实现,真正的业务逻辑实现交给接口的实现类来完成。
好处:当用户需求发生变更时,只需要切换不同的实现类,而不需要修改串联模块的接口,减少对系统的影响;
使用这种方式编程,代码的耦合度低,灵活性高且易于扩展。
接口和抽象类的关系:
接口是一个极度抽象的抽象类,接口中的方法全部都是抽象方法;抽象类中可以有非抽象方法。
接口的实现类用来实现接口中的抽象方法,将抽象的概念具体化;实现类实现接口,需要对接口内部所有抽象方法进行实现,同时要求访问权限修饰符、返回类型、方法名和参数列表完全相同。