📜  Java super

📅  最后修改于: 2020-09-26 15:40:31             🧑  作者: Mango

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

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

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


超级关键字的用途
  1. 调用在子类中重写的超类的方法。
  2. 如果超类和子类都具有相同名称的属性,则访问超类的属性(字段)。
  3. 从子类构造函数中显式调用超类no-arg(默认值)或参数化构造函数。

让我们了解所有这些用途。


1.超类的访问重写方法

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

示例1:方法覆盖

class Animal {

  // overridden method
  public void display(){
    System.out.println("I am an animal");
  }
}

class Dog extends Animal {

  // overriding method
  @Override
  public void display(){
    System.out.println("I am a dog");
  }

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

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

输出

I am a dog

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

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

Java覆盖示例

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

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

示例2:超级调用超类方法

class Animal {

  // overridden method
  public void display(){
    System.out.println("I am an animal");
  }
}

class Dog extends Animal {

  // overriding method
  @Override
  public void display(){
    System.out.println("I am a dog");
  }

  public void printMessage(){

    // this calls overriding method
    display();

    // this calls overridden method
    super.display();
  }
}

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

输出

I am a dog
I am an animal

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

super在Java中的工作


2.超类的访问属性

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

示例3:访问超类属性

class Animal {
  protected String type="animal";
}

class Dog extends Animal {
  public String type="mammal";

  public void printType() {
    System.out.println("I am a " + type);
    System.out.println("I am an " + super.type);
  }
}

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

输出

I am a mammal
I am an animal

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

然后,我们创建了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 {

  // default or no-arg constructor of class Animal
  Animal() {
    System.out.println("I am an animal");
  }
}

class Dog extends Animal {

  // default or no-arg constructor of class Dog
  Dog() {

    // calling default constructor of the superclass
    super();

    System.out.println("I am a dog");
  }
}

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

输出

I am an animal
I am a dog

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

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

Java中super()的工作

然后,程序流返回到子类构造函数,并执行其余的语句。因此, 将是一条狗将被印刷。

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

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

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

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

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

class Animal {

  // default or no-arg constructor
  Animal() {
    System.out.println("I am an animal");
  }

  // parameterized constructor
  Animal(String type) {
    System.out.println("Type: "+type);
  }
}

class Dog extends Animal {

  // default constructor
  Dog() {

    // calling parameterized constructor of the superclass
    super("Animal");

    System.out.println("I am a dog");
  }
}

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

输出

Type: Animal
I am a dog

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

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

在参数化构造函数的情况下,super的工作。

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