108. Java 继承 - 隐藏字段与 super 关键字

108 阅读4分钟

108. Java 继承 - 隐藏字段与 super 关键字

隐藏字段

在 Java 中,如果子类中声明了与超类相同名称的字段,那么该字段会隐藏超类中的字段。这意味着即使这两个字段的类型不同,子类中的字段会遮蔽掉超类中的字段,导致在子类中无法直接通过字段名访问超类的字段。相反,必须通过 super 关键字来引用超类中的字段。

不推荐隐藏字段,因为这样会导致代码不易理解和维护。尤其是在较大的类层次结构中,使用相同字段名可能会引起混淆,增加调试的复杂度。

使用 super 关键字访问超类成员
  1. 访问被覆盖的方法:当子类覆盖了超类的方法时,我们可以通过 super 关键字调用超类中的被覆盖方法。
  2. 访问隐藏的字段:如果子类隐藏了超类的字段,也可以使用 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) 调用超类的构造函数。调用超类构造函数时,必须放在子类构造函数的第一行。

  1. 无参数构造函数调用:如果超类有一个无参数构造函数,可以通过 super() 来调用。
  2. 有参数构造函数调用:如果超类有一个有参数构造函数,可以通过 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 编译器会自动插入对超类无参构造函数的调用(前提是超类有一个无参构造函数)。如果超类没有无参构造函数,将会出现编译时错误。

总结

  1. 字段隐藏:如果子类定义了与超类相同名称的字段,子类会隐藏超类的字段。推荐使用 super 关键字来引用超类的字段。
  2. 方法覆盖与 super:当子类覆盖了超类的方法,可以通过 super 调用超类的方法。
  3. 构造函数调用:子类构造函数可以通过 super()super(parameter list) 调用超类的构造函数,必须放在构造函数的第一行。

通过 super 关键字,Java 提供了访问超类成员的能力,帮助我们更好地管理类的继承结构和方法、字段的继承关系。