Java super 关键字

Java 中的 super 关键字用于在子类中访问父类成员(属性、构造方法和方法)。在本教程中,我们将通过示例了解 Java 中的 super 关键字的用法。

Java 中的 super 关键字用于在子类中访问父类成员(属性、构造方法和方法)。在本教程中,我们将通过示例学习 Java 中的 super 关键字。

在我们学习 super 关键字之前,请确保了解了 Java 继承的概念。

super 关键字作用

  1. 在子类中调用被覆盖的父类的方法。
  2. 如果父类和子类都具有同名的属性,则访问父类的属性(字段)。
  3. 从子类构造方法中显式调用父类的构造方法。

让我们了解这些用途中的每一个。

访问父类的重写方法

如果在子类中定义了和父类同名方法,则子类中的方法会覆盖父类中的方法。这称为方法覆盖

示例 1:方法覆盖

class Animal {
  public void display(){
    System.out.println("这是一只动物");
  }
}

class Dog extends Animal {
  // 覆盖父类的方法
  @Override
  public void display(){
    System.out.println("这是一只狗");
  }

  public void printMessage(){
    display();
  }
}

public class Main {
  public static void main(String[] args) {
    Dog dog1 = new Dog();
    dog1.printMessage();
  }
}

输出

这是一只狗

Java覆盖示例

如果必须调用父类的重写方法怎么办?

我们使用 super.display() 来调用父类的 display()

示例 2:super 调用父类方法

class Animal {
  public void display(){
    System.out.println("这是一只动物");
  }
}

class Dog extends Animal {
  @Override
  public void display(){
    System.out.println("这是一只狗");
  }

  public void printMessage(){
    display();

    // 调用父类的方法
    super.display();
  }
}

public class Main {
  public static void main(String[] args) {
    Dog dog1 = new Dog();
    dog1.printMessage();
  }
}

输出

这是一只狗
这是一只动物

下图展示了上面例子的调用流程:

在 Java 中使用 super

访问父类的属性

父类和子类可以具有相同名称的属性。我们使用 super 关键字来访问父类的属性。

示例 3:访问 ​​ 父类属性

class Animal {
  protected String type = "动物";
}

class Dog extends Animal {
  public String type = "哺乳动物";

  public void printType() {
    System.out.println("我是" + type);
    System.out.println("我是" + super.type);
  }
}

public class Main {
  public static void main(String[] args) {
    Dog dog1 = new Dog();
    dog1.printType();
  }
}

输出

我是哺乳动物
我是动物

在这个例子中,我们在父类 Animal 和子类 Dog 中定义了相同的实例字段 type 表示类型。

然后我们创建了一个 Dog 类的对象 dog1,然后调用此对象的 printType() 方法。

printType() 函数内部,

  • type 指的是子类 Dog 的属性。
  • super.type 指父类 Animal 的属性。

因此, System.out.println("I am a " + type); 打印 我是哺乳动物。 而 System.out.println("I am an " + super.type); 打印 我是动物.

3.使用 super() 访问父类构造方法

我们知道,当一个类的对象被创建时,它的默认构造方法会被自动调用。

我们使用 super() 从子类构造方法显式调用父类构造方法,它是 super 关键字的一种特殊形式。

super() 只能在子类构造方法中使用,并且必须是第一条语句。

示例 4:使用 super()

class Animal {
  Animal() {
    System.out.println("这是一只动物");
  }
}

class Dog extends Animal {
  Dog() {
    // 调用父类无参构造方法
    super();

    System.out.println("这是一只狗");
  }
}

public class Main {
  public static void main(String[] args) {
    Dog dog1 = new Dog();
  }
}

输出

这是一只动物
这是一只狗

在这里,当创建 dog1 对象时,它会自动调用该类构造方法 Dog() 。在子类构造方法 Dog() 内部, super() 语句调用父类的构造方法并执行其中的语句。因此,先打印 这是一只动物

在 Java 中使用 super()

然后程序流程返回到子类构造方法并执行剩余的语句。因此,再打印 这是一只狗

但是,使用 super() 不是强制性的。即使在子类构造方法中没有使用 super(),编译器也会隐式调用父类的默认构造方法。

那么,如果编译器自动调用 super(),为什么还要使用冗余代码呢?

如果必须从子类构造方法调用父类的带参数的构造方法,就要显示调用。

带参数的 super() 必须始终是子类构造方法体中的第一条语句,否则会出现编译错误。

示例 5:使用 super() 调用带参数的构造方法

class Animal {
  // 默认的构造函数
  Animal() {
    System.out.println("这是一只动物");
  }

  // 带参数的构造方法
  Animal(String type) {
    System.out.println("类型:"+type);
  }
}

class Dog extends Animal {
  // 默认的构造函数
  Dog() {
    // 调用父类带参数的构造方法
    super("动物");

    System.out.println("这是一只狗");
  }
}

public class Main {
  public static void main(String[] args) {
    Dog dog1 = new Dog();
  }
}

输出

类型:动物
这是一只狗

编译器可以自动调用无参数构造方法。但是,它不能调用带参数的构造方法。

如果必须调用带参数的构造方法,我们需要在子类构造方法中显式调用。

使用 super 调用带参数的构造方法。

请注意,在上面的示例中,我们通过 super("动物") 调用了带参数的构造方法。在这种情况下,编译器不会调用父类的默认构造方法。