面向对象进阶 继承

张开发
2026/4/13 20:42:47 15 分钟阅读

分享文章

面向对象进阶 继承
文章目录什么是继承?继承的好处?继承的特点子类到底能继承父类的哪些内容?带继承的对象内存布局堆中对象的完整内存结构继承中成员变量和成员方法的访问特点继承中构造方法的访问特点什么是继承?继承的好处?继承extends关键字,可以让一个类跟另一个类建立继承关系可以把子类中的重复代码抽取出来放到父类里,提高代码复用性格式​public class 子类 extends 父类 {}继承后子类的特点子类得到父类的属性和行为可以使用子类可以在父类的基础上新增其他功能,使子类更强大继承的特点特点java只支持单继承,不支持多继承,但支持多层继承课堂重点单继承一个子类只能继承一个父类,不能同时继承多个父类多层继承子类a继承父类b,父类b继承父类cc是a的间接父类每个类之间直接或间接继承于Object继承体系子类可以使用间接父类或父类的内容,但不可以使用同一继承体系下非父类和间接父类的内容设计继承画图法从下往上画,把子类的共性内容进行抽取,而且子类要是父类的一种书写代码从上往下写注意事项如果父类成员使用private修饰,子类就无法调用了,只能在本类中使用子类到底能继承父类的哪些内容?内存图父类中的内容哪些子类能继承?构造方法 非私有 不能 private 不能成员变量 非私有 能 private 能成员方法 非私有 能 private 不能如果子类继承父类构造方法,那构造方法名不再是类名,无法被虚拟机调用,因此不允许继承构造方法成员变量不管非私有还是private都会被继承,不过private的变量无法进行使用,但可以通过get和set方法使用带继承的内存图,相比之前区别是加载自解码文件时会加载父类的自解码文件,堆里创建对象的时候会有一部分区域创建父类里继承的对象带继承的对象内存布局​ 类加载的先后顺序继承场景当代码中出现new Son()时JVM 的类加载流程是先加载父类检查父类是否已加载若未加载先加载父类的.class文件到元空间方法区生成对应的InstanceKlass元数据包含父类的字段表、方法表、虚方法表等再加载子类父类加载完成后加载子类的.class文件到元空间生成子类的InstanceKlass元数据简单理解JVM 必须先 “认识” 父类才能 “认识” 子类。堆中对象的完整内存结构以Son extends Father为例new Son()后堆中对象的内存分为三部分内存区域具体内容按顺序排列对象头包含Mark Word哈希码、GC 年龄、锁状态和Klass Pointer指向元空间中子类的InstanceKlass元数据。父类实例数据父类的所有成员变量包括private私有变量按父类中定义的顺序排列。注意私有变量只是 “访问权限限制”内存中依然存在。子类实例数据子类自己新增的成员变量按定义顺序排列。对齐填充保证对象总大小是 8 字节的倍数HotSpot 要求对象大小必须是 8 字节的整数倍。对象头的理解:对象类型对象头组成部分64 位 JVM默认开启压缩指针64 位 JVM关闭压缩指针普通对象Mark Word标记字段8 字节固定不变8 字节固定不变普通对象Klass Pointer类型指针4 字节8 字节标记字段专门存储对象自身运行时的原生状态数据这些数据和类的元数据、继承无关是 JVM 管理对象的底层依赖比如垃圾回收、并发锁控制都完全依赖 Mark Word。JVM 通过对象的这个指针就能立刻知道「这个对象是哪个类的实例」以及这个类的所有信息继承关系、字段、方法、虚方法表等。类型指针Klass Pointer 是一个内存地址指针它指向元空间方法区中该对象所属类的InstanceKlass元数据实例是堆中对象实例和类的元数据之间的唯一桥梁。永远指向当前对象实际类型的元数据父类的信息是存在当前类的元数据内部的。Klass Pointer 存在堆里的对象头中它指向的目标InstanceKlass存在元空间里。创建对象调用方法的规则:如果从创建的对象开始找,没找到就找对应的父类,那继承结构复杂后效率太低了.java实际会在最顶层设立虚方法表,把经常使用的方法存放到这里.需要方法不被private,static和final修饰,这样的方法称为虚方法.继承后子类会得到父类的虚方法表并为里面扩充新的虚方法.如果调用的不是虚方法,程序就会一层层去找,只有父类里的虚方法子类才会继承虚方法表的存储位置与结构存储位置虚方法表vtable不是存在堆里而是存在元空间方法区中作为类的InstanceKlass元数据的一部分,还有super_class和字段表也是存在InstanceKlass元数据里表的结构虚方法表是一个数组每个元素是一个方法入口地址指向该方法在元空间中的字节码 / 机器码每个方法有一个固定的索引从 0 开始。继承场景下虚方法表的生成逻辑以Son extends Father为例虚方法表的生成分为 3 步父类先生成自己的虚方法表把父类的所有虚方法按顺序放入表中分配索引比如索引 0、1、2…子类复制父类的虚方法表子类加载时先完整复制父类的虚方法表包括父类虚方法的索引和入口地址子类扩充自己的虚方法表若子类新增了虚方法把新方法追加到虚方法表的末尾索引继续递增若子类重写了父类的虚方法把虚方法表中对应索引位置的入口地址替换成子类重写后的方法地址覆盖父类的旧地址。虚方法表的继承逻辑先复制父类表再覆盖 / 追加方法重写的本质覆盖虚方法表中对应索引的方法入口地址这也是为什么重写要求方法名 / 形参必须一致 —— 保证索引能对应上每个类的虚方法表只生成一次存于元空间该类的所有对象共享同一张虚方法表通过对象头的Klass Pointer找到。继承中成员变量和成员方法的访问特点继承中成员变量的访问特点就近原则谁离我近就访问谁super关键字:表示父类,调用父类的对应变量this关键字:表示类,调用类里的实例变量继承中成员方法的访问特点直接调用满足就近原则,super调用直接访问父类方法的重写当父类的方法不能满足子类现在的需求时,需要进行方法的重写在继承体系中,子类里出现了和父类一模一样的方法声明,称子类里的方法是重写的方法Override重写注解是放在重写后的方法上,校验子类重写时语法是否正确,与注释不同的是,这个标识可以被编译器识别本质覆盖继承到的虚方法表注意事项方法名和形参列表必须与父类一致子类重写父类时,访问权限必须大于等于父类子类重写父类方法时,返回值类型子类必须小于等于父类(子类是父类的子集,返回值类型不会比父类大)重写父类时尽量和父类保持一致只有被添加到虚方法表的方法才能被重写继承中构造方法的访问特点继承中构造方法的访问特点子类不会继承父类的构造方法子类中所有的构造方法默认先访问父类中的无参构造,再执行自己子类在初始化的时侯可能用到父类中的数据,如果父类没有初始化就会报错子类构造方法的第一行默认是super(),不写也存在且必须在第一行如果想调用父类的有参构造,必须手动写super调用

更多文章