Chapter08
包
命名规则
只能数字、字母、下划线、小圆点。不能数字开头,不能包含关键字或保留字。
命名规范
com.公司.项目名.业务模块名
访问修饰符
- public:对外公开
- protected:对子类和同一包中的类公开
- 没有修饰符:默认级别,向同一个包的类公开
- private:只有类本身可以访问,不对外公开
访问级别 | 访问修饰符 | 本类 | 同包 | 子类 | 不同包 |
---|---|---|---|---|---|
公开 | public | ✔ | ✔ | ✔ | ✔ |
受保护 | protected | ✔ | ✔ | ✔ | ❌ |
默认 | 无 | ✔ | ✔ | ❌(不同包)✔(同包) | ❌ |
私有 | private | ✔ | ❌ | ❌ | ❌ |
- 只有默认和public修饰类
OOP特征
封装
将类中的属性和方法封装起来,外部只能通过相应方法访问和修改。
实现方法:
-
private修饰方法和属性
-
创建public修饰的访问方法 (快捷键alt + Insert)
public void setXxx(类型 参数名) { // 加入数据验证和业务逻辑 属性 = 参数名; }
-
创建public修饰的获取方法
public xxx getXxx() { // 增加对当前对象的权限判断 return xxx; }
如果与构造器相结合,将setXxx()方法写入构造器中。
继承
可以解决代码复用,多个类有相同的属性和方法,抽象一个父类,将相同的属性和方法定义在父类中,子类extends即可。子类又叫派生类,父类又叫超类、基类。
注意:
-
子类继承了父类所有的属性和方法,但是不能访问private属性,需要通过父类公共的方法访问。
-
子类必须调用父类的构造器,完成父类的初始化。
-
创建子对象时,不管使用子类的哪个构造器,默认情况下总会调用父类的无参构造器。若父类没有定义无参构造器,则在子类需用super来指定调用父类的哪个构造器,完成初始化。
-
super()只能在子类构造器第一行。
-
在子类中调用父类的某个构造器时,显示调用:super(参数列表);
-
super(); this();都只能放在构造器的第一行,因此不能存在同一个构造器中。
-
Object类是所有类的基类。
-
父类构造器的调用不限于直接父类,将一直追溯到Object类。
-
子类最多只能继承一个父类,java中是单继承机制。
-
不能滥用继承,子类和父类之间必须满足相应的逻辑关系。
(Music extends Person ❌)(Cat extends Animal ✔)
继承的本质
按照查找关系返回信息:首先查看子类是否有该属性,有且可以访问就返回;如果没有,向父类查找,有且可以访问就返回,逐渐向上查找至Object类。
若在查找过程中,找到了,但是不能访问,则报错;若没有找到,提示方法不存在。
super关键字
代表父类的引用,可以访问父类的属性、方法、构造器。
cal(); // 等价于 this.cal();
super.cal(); // 在父类中查找方法
- 多个基类有相同的成员方法,super访问遵循就近原则。
区别 | this | super |
---|---|---|
访问属性 | 访问本类,若没有从父类查找 | 从父类开始查找 |
调用方法 | 访问本类,若没有从父类查找 | 从父类开始查找方法 |
调用构造器 | 调用本类的构造器,放在构造器首行 | 调用父类构造器,放在子类构造器首行 |
特殊 | 表示当前对象 | 子类中访问父类对象 |
多态
方法重写与重载体现多态
- 子类方法的参数、方法名与父类一样;
- 子类方法的返回类型与父类一样,或者是父类的子类;
- 子类方法不能缩小父类方法的访问权限。
名称 | 发生范围 | 方法名 | 形参列表 | 返回类型 | 修饰符 |
---|---|---|---|---|---|
重载(overload) | 本类 | 一样 | 类型、个数、顺序至少一个不同 | 无要求 | 无要求 |
重写(override) | 父子类 | 一样 | 相同 | 重写的方法返回类型和父类的一致或者是其子类 | 子类方法不能缩小父类的访问范围 |
对象的多态
- 一个对象的编译类型和运行类型可以不一致
- 编译类型在定义对象时就确定了,不能改变
- 运行类型是可以改变的
- 编译类型看类定义时等号的左边,运行类型看等号的右边
注意:
-
前提是两个对象存在
继承
关系 -
向上转型,本质就是
父类的引用指向子类的对象
。可以调用父类所有成员(遵守访问权限),子类中特有成员不能调用。最终的实现效果需要看子类的具体体现。 -
在编译阶段,能调用哪些成员,由编译类型决定;在运行阶段,
调用方法
从子类(运行类型)开始查找。// 向上转型 Animal animal = new Cat();
-
向下转型
// 向下转型 Cat cat = (Cat) animal;
- 语法:子类类型 引用名 = (子类类型) 父类引用
- 只能强转
父类的引用
,不能强转父类的对象 要求父类的引用必须指向的是当前目标类型的对象
- 可以调用子类类型中所有的成员
-
属性没有重写,属性的值直接看编译类型。
-
instanceof比较操作符,判断对象的运行类型是否为XX类型或XX类型的子类型。
动态绑定机制
当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定,调用对象属性时,没有动态绑定机制。
多态应用
多态数组
数组的定义类型为父类类型,其中元素类型为子类类型。
Person[] persons = new Person[5];
persons[0] = new Person("tom", 20);
persons[1] = new Student("jerry", 18, 95);
persons[2] = new Student("jack", 19, 96);
persons[3] = new Teacher("smith", 32, 20000);
persons[4] = new Teacher("king", 42, 25000);
// 循环遍历多态数组,调用方法的动态绑定机制
for (int i = 0; i < persons.length; i++) {
System.out.println(persons[i].say());
}
结果:
tom 20
jerry 18 score 95.0
jack 19 score 96.0
smith 32 salary 20000.0
king 42 salary 25000.0
多态参数
方法定义的形参类型为父类类型,实参类型为子类类型。
public class Test {
public static void main(String[] args) {
Staff yang = new Staff("yang", 20000);
showEmpAnnal(yang);
testWork(yang);
Manager ali = new Manager("ali", 30000, 250000);
showEmpAnnal(ali);
testWork(ali);
}
public static void showEmpAnnal(Employee e) {
// 动态绑定机制
System.out.println(e.getAnnual());
}
public static void testWork(Employee e) {
if (e instanceof Staff) {
// 向下转型
((Staff) e).work();
} else if (e instanceof Manager) {
((Manager) e).manage();
} else {
System.out.println("不做处理");
}
}
}
结果:
240000.0
Staff yang is working...
610000.0
Manager ali is management
Object类详解
equals(Object obj); // 指示其他某个对象是否与此对象“相等”
hashCode(); // 返回该对象的哈希码值
toString(); // 返回该对象的字符串表示
finalize(); // 当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法
getClass(); // 返回此 Object 的运行时类
-
"=="与equals比较
"=="可以判断基本类型和引用类型,分别判断基本类型的值和引用类型的地址是否相等。
equals只能用于判断引用类型,默认判断地址是否相等,子类会重写该方法,用于判断内容是否相等,如Integer、String子类判断内容是否相等。
-
hashCode方法
- 提高具有哈希结构的容器的效率
- 两个引用指向同一个对象,哈希值一样,如果指向不同的对象,哈希值不一样
- 哈希值是由地址计算出来的,二者不同
- 在集合中hashCode重写
-
toString方法
默认返回:全类名(包名、类名) + @ + 哈希值的十六进制。
子类重写toString方法,用于返回对象的属性信息。打印或者拼接对象时,会自动调用该对象的toString形式。
// 当直接输出一个对象时,toString方法会默认调用。 System.out.println(person); // 默认调用person.toString();
-
finalize方法
- 回收对象时,系统自动调用该对象的finalize方法,子类可以重写该方法,做一些释放资源的操作(程序员的自己业务逻辑代码)。
- 当某个对象没有任何引用时,JVM机将该对象看作垃圾对象,用垃圾回收机制进行回收该对象时就会调用该方法。
- 系统决定垃圾回收机制的调用(垃圾回收算法 ),也可通过System.gc()主动出发垃圾回收机制。