掌握 Java 中的 SUPER 关键字:解锁继承和构造函数链
阅读:33
点赞:0
在这篇文章中,我们将深入探讨 Java 中的 super
关键字,分析其在不同场景下的工作原理。文章分为两个部分,第一部分介绍如何使用 super
访问父类的方法和变量,第二部分解释构造函数链的概念及其细节。
一. 使用 super 访问父类的方法和变量
super
关键字允许子类重用父类的功能,包括方法和变量。当你想要执行以下操作时,super
尤其有用:
-
调用父类被重写的方法。 -
访问当子类与父类同名变量时隐藏的变量。
示例代码:
父类
package super_keyword;
class EmployeeParent {
private int id, depId; // 员工ID和部门ID
protected String name; // 员工姓名
private double basicSal; // 基本薪资
public EmployeeParent(int id, String name, int depId, double basicSal) {
this.id = id; // 初始化员工ID
this.name = name; // 初始化员工姓名
this.depId = depId; // 初始化部门ID
this.basicSal = basicSal; // 初始化基本薪资
}
// 父类方法计算净薪资
protected double computeNetSalary() {
return basicSal; // 返回基本薪资
}
@Override
public String toString() {
return "EmployeeParent [id=" + id + ", depId=" + depId +
", name=" + name + ", basicSal=" + basicSal + "]"; // 返回员工信息
}
}
子类
class ManagerChild extends EmployeeParent {
private double perfBonus; // 绩效奖金
public ManagerChild(int id, String name, int depId, double basicSal, double perfBonus) {
super(id, name, depId, basicSal); // 调用父类构造函数
this.perfBonus = perfBonus; // 初始化绩效奖金
}
// 重写父类方法
@Override
public double computeNetSalary() {
// 使用 super 调用父类方法
/* 在这里不使用 super 关键字,编译器会认为我们正在
使用递归,最终导致 StackOverflowError 异常。 */
return perfBonus + super.computeNetSalary();
}
@Override
public String toString() {
// 使用 super 重用父类的 toString()
return "ManagerChild [perfBonus=" + perfBonus + ", " +
super.toString() + "]"; // 返回经理信息
}
public void displayParentName() {
// 访问父类变量
System.out.println("Employee's Name: " + super.name); // 输出员工姓名
}
public static void main(String[] args) {
ManagerChild manager = new ManagerChild(1, "Arshi", 2, 10000, 1890);
System.out.println(manager); // 输出经理信息
System.out.println("Net Salary: " + manager.computeNetSalary()); // 输出净薪资
manager.displayParentName(); // 显示父类的姓名
}
}
代码解释:
-
访问父类方法: 在 computeNetSalary()
方法中,super.computeNetSalary()
调用了父类的版本。 -
访问父类变量: displayParentName()
方法演示了如何使用super
访问父类的变量(name
)。 -
调用父类构造函数: super(id, name, ...)
用于通过调用父类构造函数初始化公共字段。
二. 构造函数链与 super()
构造函数链是 Java 中的一个强大特性,它允许子类构造函数调用父类构造函数,以确保在执行子类的构造函数之前,父类被正确初始化。
super()
关键字在这个过程中发挥着重要作用。让我们探索构造函数链的细节及其运作方式。
构造函数链的关键概念:
-
子类构造函数必须调用父类构造函数: 在 Java 中,每个子类构造函数必须调用父类的某个构造函数。这对于在类层次结构中建立正确的初始化顺序至关重要。
示例代码:
package constructor_chaining;
public class ConstructorChainingParent {
// 父类默认构造函数
public ConstructorChainingParent() {
System.out.println("Parent DEFAULT Constructor Called"); // 输出父类默认构造函数调用
}
// 带一个参数的父类构造函数
public ConstructorChainingParent(String name) {
System.out.println("Parent PARAMETERIZED Constructor Called with name: " + name); // 输出调用信息
}
// 带两个参数的父类构造函数
public ConstructorChainingParent(String name, int id) {
System.out.println("Parent PARAMETERIZED Constructor Called with name: " + name + " and id: " + id); // 输出调用信息
}
}
子类
public class ConstructorChainingChild extends ConstructorChainingParent {
// 子类默认构造函数
public ConstructorChainingChild() {
// 编译器自动插入 super() 调用
System.out.println("Child DEFAULT Constructor Called"); // 输出子类默认构造函数调用
}
// 带一个参数的子类构造函数
public ConstructorChainingChild(String name) {
super(name); // 调用父类带一个参数的构造函数
System.out.println("Child PARAMETERIZED Constructor Called with name: " + name); // 输出调用信息
}
// 带两个参数的子类构造函数
public ConstructorChainingChild(String name, int id) {
super(name, id); // 调用父类带两个参数的构造函数
System.out.println("Child PARAMETERIZED Constructor Called with name: " + name + " and id: " + id); // 输出调用信息
}
public static void main(String[] args) {
// 创建子类实例
ConstructorChainingChild child = new ConstructorChainingChild();
// 输出:
// Parent DEFAULT Constructor Called
// Child DEFAULT Constructor Called
// 创建带一个参数的子类实例
ConstructorChainingChild child1 = new ConstructorChainingChild("Alice");
// 输出:
// Parent PARAMETERIZED Constructor Called with name: Alice
// Child PARAMETERIZED Constructor Called with name: Alice
// 创建带两个参数的子类实例
ConstructorChainingChild child2 = new ConstructorChainingChild("Bob", 1);
// 输出:
// Parent PARAMETERIZED Constructor Called with name: Bob and id: 1
// Child PARAMETERIZED Constructor Called with name: Bob and id: 1
}
}
代码解释:
-
显式调用父类构造函数: 在 ConstructorChainingChild
类的构造函数中,调用了ConstructorChainingParent
类的构造函数。 -
默认构造函数的隐式调用: 如果没有显式调用父类的构造函数,编译器会自动插入对默认构造函数的调用。
三. 总结
理解如何有效地使用 super
可以提升你的 Java 编程能力,特别是在复杂的继承场景中。掌握这些概念对于编程面试也至关重要,因为它展示了你对面向对象原则的理解。