继承基础
class A {
int i;
void m() {
// body
}
}
class B extends A {
int k;
void n() {
// body
}
}
没有类可以成为其自身的超类(super class)。
子类不能访问超类中的 private 成员。
超类类型变量可以引用派生自该超类的子类对象,但是使用该变量只能访问超类中定义的成员,不能访问子类中特有的成员。
使用 super
子类想调用直接超类的构造器时,在构造器中使用 super()
语句,该语句代表调用超类的构造器。这个语句必须位于子类构造器中第一行(也就是作为构造器的第一条语句)。
在子类中可以使用 super
表示超类,用来访问直接超类中的成员,形式为 super.member
,主要用来在子类中访问被子类中定义的变量隐藏的超类中同名的变量。
多层继承
每一层级类的 super
表示直接超类。
构造器的执行
在类的继承层次中,当某个类初始化时,初始化的顺序是回溯到该类最上面的超类,然后根据继承顺序依次调用每一层类的构造器,直到最后执行该类的构造器。
方法重写(overriding)
子类中定义的某个方法的类型签名与超类中的某个方法完全一致,则子类对象在调用该方法时,调用的是子类中定义的方法,而超类中同名的方法被隐藏,如果想要调用超类中的方法,需要在子类中使用 super
。
动态方法调度(dispatch)
动态方法调用是指运行时,解析重写的方法。
当超类变量引用子类对象时,如果子类中存在重写的父类方法,则在调用该方法时,调用的是子类中定义的方法。也就是在运行时调用的重写方法由对象而不是变量决定。
使用抽象类
抽象方法:
abstract type name(parameterList);
包含一个或多个抽象方法的类必须定义为抽象类。抽象类的子类要么实现抽象类中的全部抽象方法,此时该子类为非抽象类;要么必须定义为抽象类(没有实现全部抽象方法)。抽象类中可以包含非抽象方法。
抽象类不能直接使用 new 实例化,但可以作为变量的类型。不能定义抽象构造器和抽象静态方法。
final 用于继承
final type name(parameterList) {
// body
}
final 方法不能被重写。final 方法有时会被编译器 inline 调用,此时可以提高性能。在运行时解析方法调用称为 late binding,在编译时解析方法调用(如 final 方法)称为 early binding。
final 修饰的类不能被继承,同时表示该类中所有方法都是 final 方法。
一个类不能同时被 abstract 和 final 修饰。
局部变量类型推导和继承
当一个方法可以返回不同的类(这些类有着继承关系),使用局部变量类型推导作为该方法的目标类型时,变量类型由该方法定义时的返回类型决定,而不是由实际返回对象的类型决定。
Object 类
toString()
方法返回对象的描述。在 println 语句中输出对象时,会调用对象的 toString()
方法。
参考
[1] Herbert Schildt, Java The Complete Reference 11th, 2019.