继承的定义
继承(inheritance)是面向对象中的一个概念。它使得复用以前的代码非常容易。
在 Java 语言中继承就是子类继承父类的属性和方法,使得子类对象(实例)具有父类的属性和方法,或子类从父类继承方法,使得子类具有父类相同的方法。
继承的优缺点
优点:
- 代码复用:子类可以复用父类的代码,减少重复实现。
- 易于维护:可以通过修改父类代码来影响所有子类。
缺点:
- 紧耦合:子类依赖于父类的实现,父类的修改可能会影响子类。
- 灵活性差:继承层次结构可能会变得复杂,不易于调整或扩展。
继承的特点
- Java不允许多重继承(一个子类同时继承多个父类)但是支持多层继承,一个类只能继承一个父类
Object
类是所有类中的公共父类- 继承当中子类抛出的异常必须是父类抛出的异常或父类抛出异常的子异常
- 子类可以继承父类的部分属性和方法
继承的语法实现
|
|
子类继承的内容
父类的所有属性
子类继承父类的所有的属性(但是被private
修饰的变量被隐藏无法直接使用)
如果要使用父类的private
属性可以通过父类的getter
方法和setter
方法
父类的构造方法不能被继承
父类的构造方法不能被子类继承:因为构造方法语法是与类同名,而继承则不更改方法名,如果子类继承父类的构造方法,那明显与构造方法的语法冲突了。
成员方法(虚方法)
方法传递机制
Java虚拟机从最顶级的父类开始设置虚方法表,父类会将虚方法表传递给自己的子类,然后在父类的虚方法表的基础上添加自己的虚方法从而形成自己的虚方法表
虚方法的条件
- 非
static
- 非
final
- 非
private
只有虚方法表中的方法会被子类继承
super关键字
super
关键字用于指代父类的存储空间
- 指向父类对象;
- 调用父类的方法;
super()
可以调用父类的无参构造方法。
继承中成员变量调用规则
成员变量的调用规则满足就近原则
寻找顺序为:方法局部位置——>本类的成员位置——>父类成员位置
逐级向上寻找
使用this
直接调用本类的变量
使用super
调用父类的变量
继承中成员方法调用规则
直接调用
成员方法的调用规则满足就近原则
寻找顺序为:方法局部位置——>本类的成员方法——>父类成员方法
逐级向上寻找
使用this
直接调用本类的方法
使用super
调用父类的方法
方法重写
子类中重写父类中的方法,保持返回值类型,方法名,参数列表不变,它建立在继承的基础上。
重写条件
- 重写方法的名称、形参列表必须与父类中的一致。
- 子类重写父类方法时,访问权限子类必须大于等于父类(
default
<protected
<public
) - 子类重写父类方法时,返回值类型子类必须小于等于父类
- 只有被添加到虚方法表中的方法才能被重写(静态方法,私有方法,被
final
修饰的方法不能重写) - 继承当中子类抛出的异常必须是父类抛出的异常或父类抛出异常的子异常
底层实现
子类重写的新方法覆盖从父类继承来的虚方法表中父类的同名方法
示例代码
|
|
构造方法
- 子类的所有构造方法默认必须调用其父类的构造方法再执行自己的构造方法:Java 虚拟机构造子类对象前会先构造父类对象,父类对象构造完成之后再来构造子类特有的属性,这被称为内存叠加。
- 如果子类的构造方法中没有显式地调用父类构造方法,则系统默认调用父类无参数的构造方法:所有子类的构造方法第一行必须为
super()
- 任何情况下实例化对象会调用继承链的所有父类构造方法
- 子类无法继承父类的构造方法但是可以通过
super
关键字来调用 - 当父类只有有参构造函数时,子类必须显式调用
super
并传入合适的参数。
示例代码
|
|
继承中类的加载顺序
在Java继承中,父子类初始化先后顺序为:
- 父类中静态成员变量和静态代码块
- 子类中静态成员变量和静态代码块
- 父类中普通成员变量和代码块,父类的构造函数
- 子类中普通成员变量和代码块,子类的构造函数
总的来说,就是静态>非静态,父类>子类,非构造函数>构造函数。同一类别(例如普通变量和普通代码块)成员变量和代码块执行从前到后,需要注意逻辑。