掌握 Java 中的 SUPER 关键字:解锁继承和构造函数链

发布:2024-10-18 10:21 阅读: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"2100001890);
        System.out.println(manager); // 输出经理信息
        System.out.println("Net Salary: " + manager.computeNetSalary()); // 输出净薪资
        manager.displayParentName(); // 显示父类的姓名
    }
}

代码解释:

  1. 访问父类方法:computeNetSalary() 方法中,super.computeNetSalary() 调用了父类的版本。
  2. 访问父类变量: displayParentName() 方法演示了如何使用 super 访问父类的变量(name)。
  3. 调用父类构造函数: super(id, name, ...) 用于通过调用父类构造函数初始化公共字段。

二. 构造函数链与 super()

构造函数链是 Java 中的一个强大特性,它允许子类构造函数调用父类构造函数,以确保在执行子类的构造函数之前,父类被正确初始化。

super() 关键字在这个过程中发挥着重要作用。让我们探索构造函数链的细节及其运作方式。

构造函数链的关键概念:

  1. 子类构造函数必须调用父类构造函数: 在 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 编程能力,特别是在复杂的继承场景中。掌握这些概念对于编程面试也至关重要,因为它展示了你对面向对象原则的理解。