原文: https://www.programiz.com/java-programming/super-keyword

在本教程中,我们将借助示例学习 Java 中的super关键字。

Java 中的super关键字在子类中用于访问超类成员(属性,构造器和方法)。

在学习super关键字之前,请确保了解 Java 继承


super关键字的用途

  1. 调用在子类中覆盖的超类的方法。
  2. 如果超类和子类都具有相同名称的属性,则访问超类的属性(字段)。
  3. 从子类构造器中显式调用超类无参(默认)或参数化构造器。

让我们了解其中的每种用法。


1.访问超类的被覆盖方法

如果在超类和子类中都定义了相同名称的方法,则子类中的方法将覆盖超类中的方法。 这称为方法覆盖的方法。

示例 1:方法覆盖

  1. class Animal {
  2. // overridden method
  3. public void display(){
  4. System.out.println("I am an animal");
  5. }
  6. }
  7. class Dog extends Animal {
  8. // overriding method
  9. @Override
  10. public void display(){
  11. System.out.println("I am a dog");
  12. }
  13. public void printMessage(){
  14. display();
  15. }
  16. }
  17. class Main {
  18. public static void main(String[] args) {
  19. Dog dog1 = new Dog();
  20. dog1.printMessage();
  21. }
  22. }

输出

  1. I am a dog

在此示例中,通过使Dog类的对象dog1,我们可以调用其方法printMessage(),该方法然后执行display()语句。

由于在两个类中都定义了display(),因此Dog子类的方法将覆盖Animal超类的方法。 因此,将调用子类的display()

Java `super` - 图1

如果必须调用超类的被覆盖方法怎么办?

如果需要调用超类Animal的覆盖方法display(),则使用super.display()

示例 2:super调用超类方法

  1. class Animal {
  2. // overridden method
  3. public void display(){
  4. System.out.println("I am an animal");
  5. }
  6. }
  7. class Dog extends Animal {
  8. // overriding method
  9. @Override
  10. public void display(){
  11. System.out.println("I am a dog");
  12. }
  13. public void printMessage(){
  14. // this calls overriding method
  15. display();
  16. // this calls overridden method
  17. super.display();
  18. }
  19. }
  20. class Main {
  21. public static void main(String[] args) {
  22. Dog dog1 = new Dog();
  23. dog1.printMessage();
  24. }
  25. }

输出

  1. I am a dog
  2. I am an animal

在这里,上述程序是如何工作的。

Java `super` - 图2


2.访问超类的属性

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

示例 3:访问超类属性

  1. class Animal {
  2. protected String type="animal";
  3. }
  4. class Dog extends Animal {
  5. public String type="mammal";
  6. public void printType() {
  7. System.out.println("I am a " + type);
  8. System.out.println("I am an " + super.type);
  9. }
  10. }
  11. class Main {
  12. public static void main(String[] args) {
  13. Dog dog1 = new Dog();
  14. dog1.printType();
  15. }
  16. }

输出

  1. I am a mammal
  2. I am an animal

在此示例中,我们在超类Animal和子类Dog中都定义了相同的实例字段type

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

printType()函数内,

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

因此,System.out.println("I am a " + type);打印I am a mammal。 而且,System.out.println("I am an " + super.type);打印I am an animal


3.使用super()访问超类构造器

众所周知,创建类的对象时,将自动调用其默认构造器。

要从子类构造器中显式调用超类构造器,我们使用super()。 这是super关键字的一种特殊形式。

super()仅可在子类构造器中使用,并且必须是第一条语句。

示例 4:使用super()

  1. class Animal {
  2. // default or no-arg constructor of class Animal
  3. Animal() {
  4. System.out.println("I am an animal");
  5. }
  6. }
  7. class Dog extends Animal {
  8. // default or no-arg constructor of class Dog
  9. Dog() {
  10. // calling default constructor of the superclass
  11. super();
  12. System.out.println("I am a dog");
  13. }
  14. }
  15. class Main {
  16. public static void main(String[] args) {
  17. Dog dog1 = new Dog();
  18. }
  19. }

输出

  1. I am an animal
  2. I am a dog

在这里,当创建Dog类的对象dog1时,它将自动调用该类的默认或无参数构造器。

在子类构造器中,super()语句调用超类的构造器并在其中执行该语句。 因此,我们得到输出我是动物。

Java `super` - 图3

然后,程序流返回到子类构造器,并执行其余的语句。 因此,将打印我是狗。

但是,不是必须使用super()。 即使在子类构造器中未使用super(),编译器也会隐式调用超类的默认构造器。

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

如果必须从子类构造器中调用超类的参数化构造器(带有参数的构造器),则是必需的。

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

示例 5:使用super()调用参数化构造器

  1. class Animal {
  2. // default or no-arg constructor
  3. Animal() {
  4. System.out.println("I am an animal");
  5. }
  6. // parameterized constructor
  7. Animal(String type) {
  8. System.out.println("Type: "+type);
  9. }
  10. }
  11. class Dog extends Animal {
  12. // default constructor
  13. Dog() {
  14. // calling parameterized constructor of the superclass
  15. super("Animal");
  16. System.out.println("I am a dog");
  17. }
  18. }
  19. class Main {
  20. public static void main(String[] args) {
  21. Dog dog1 = new Dog();
  22. }
  23. }

输出

  1. Type: Animal
  2. I am a dog

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

如果必须调用参数化的构造器,则需要在子类构造器中显式定义它。

Java `super` - 图4

请注意,在上面的示例中,我们显式调用了参数化构造器super("Animal")。 在这种情况下,编译器不会调用超类的默认构造器。