108. Java 继承 - 隐藏字段与 super 关键字
隐藏字段
在 Java 中,如果子类中声明了与超类相同名称的字段,那么该字段会隐藏超类中的字段。这意味着即使这两个字段的类型不同,子类中的字段会遮蔽掉超类中的字段,导致在子类中无法直接通过字段名访问超类的字段。相反,必须通过 super 关键字来引用超类中的字段。
不推荐隐藏字段,因为这样会导致代码不易理解和维护。尤其是在较大的类层次结构中,使用相同字段名可能会引起混淆,增加调试的复杂度。
使用 super 关键字访问超类成员
- 访问被覆盖的方法:当子类覆盖了超类的方法时,我们可以通过
super关键字调用超类中的被覆盖方法。 - 访问隐藏的字段:如果子类隐藏了超类的字段,也可以使用
super关键字来引用超类中的字段。
示例 1:访问被覆盖的方法
我们先来看一个简单的例子,子类如何通过 super 访问超类的方法:
public class Superclass {
public void printMethod() {
System.out.println("Printed in Superclass.");
}
}
public class Subclass extends Superclass {
// 重写了 Superclass 的 printMethod 方法
public void printMethod() {
super.printMethod(); // 调用超类的方法
System.out.println("Printed in Subclass");
}
public static void main(String[] args) {
Subclass s = new Subclass();
s.printMethod(); // 调用的是 Subclass 中的方法
}
}
输出:
Printed in Superclass.
Printed in Subclass
在这个例子中,Subclass 重写了 printMethod 方法,并在其内部通过 super.printMethod() 调用了超类 Superclass 中的 printMethod。这演示了如何通过 super 访问超类的方法。
示例 2:访问隐藏字段
假设我们在子类中隐藏了超类中的字段,使用 super 来访问超类的字段:
public class Superclass {
public String name = "Superclass Name";
}
public class Subclass extends Superclass {
public String name = "Subclass Name";
public void printNames() {
System.out.println("Name in Subclass: " + this.name); // 访问子类字段
System.out.println("Name in Superclass: " + super.name); // 访问超类字段
}
public static void main(String[] args) {
Subclass s = new Subclass();
s.printNames();
}
}
输出:
Name in Subclass: Subclass Name
Name in Superclass: Superclass Name
在这个例子中,name 字段在 Subclass 中被隐藏,但我们可以通过 super.name 来访问 Superclass 中的 name 字段。
子类构造函数与 super 关键字
调用超类构造函数
当子类继承了超类时,子类的构造函数可以通过 super() 或 super(parameter list) 调用超类的构造函数。调用超类构造函数时,必须放在子类构造函数的第一行。
- 无参数构造函数调用:如果超类有一个无参数构造函数,可以通过
super()来调用。 - 有参数构造函数调用:如果超类有一个有参数构造函数,可以通过
super(parameter list)调用。
示例:
public class Bicycle {
private int cadence;
private int speed;
private int gear;
public Bicycle(int startCadence, int startSpeed, int startGear) {
cadence = startCadence;
speed = startSpeed;
gear = startGear;
}
public void printDescription() {
System.out.println("Bike is in gear " + gear + " with a cadence of " + cadence + " and travelling at a speed of " + speed + ".");
}
}
public class MountainBike extends Bicycle {
private int seatHeight;
public MountainBike(int startHeight, int startCadence, int startSpeed, int startGear) {
super(startCadence, startSpeed, startGear); // 调用超类构造函数
seatHeight = startHeight;
}
public void printDescription() {
super.printDescription();
System.out.println("Seat height is " + seatHeight + ".");
}
public static void main(String[] args) {
MountainBike mb = new MountainBike(20, 10, 5, 3);
mb.printDescription();
}
}
输出:
Bike is in gear 3 with a cadence of 10 and travelling at a speed of 5.
Seat height is 20.
在这个例子中,MountainBike 的构造函数通过 super(startCadence, startSpeed, startGear) 调用了超类 Bicycle 的构造函数。这是必需的,因为 Bicycle 的构造函数没有无参构造函数,且我们需要初始化 Bicycle 类的字段。
构造函数链接
构造函数链接是指一个类的构造函数通过 super() 或 this() 调用父类或同一类中的其他构造函数。当继承层次较长时,构造函数会从子类开始,一直到顶层的 Object 类。
无显式构造函数的情况下
如果子类构造函数没有显式调用超类构造函数,Java 编译器会自动插入对超类无参构造函数的调用(前提是超类有一个无参构造函数)。如果超类没有无参构造函数,将会出现编译时错误。
总结
- 字段隐藏:如果子类定义了与超类相同名称的字段,子类会隐藏超类的字段。推荐使用
super关键字来引用超类的字段。 - 方法覆盖与
super:当子类覆盖了超类的方法,可以通过super调用超类的方法。 - 构造函数调用:子类构造函数可以通过
super()或super(parameter list)调用超类的构造函数,必须放在构造函数的第一行。
通过 super 关键字,Java 提供了访问超类成员的能力,帮助我们更好地管理类的继承结构和方法、字段的继承关系。