跳到主要内容

Java super 关键字

提示
  1. super 关键字的作用super关键字在Java中用于在子类中访问父类的成员(包括属性、方法和构造函数)。
  2. 调用父类方法和属性:当子类重写父类的方法时,可以使用super来调用被重写的父类方法。同样,当子类和父类有相同的属性时,super用于访问父类的属性。
  3. 在构造函数中使用supersuper()用于在子类构造函数中显式调用父类的构造函数,无论是无参还是带参数的构造函数。如果省略,Java编译器会自动调用父类的无参构造函数。

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

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

super 关键字的用途

  1. 调用在子类中被重写的超类方法。
  2. 如果超类和子类都有同名的属性(字段),则用来访问超类的属性。
  3. 在子类构造函数中显式调用超类的无参(默认)或带参数的构造函数。

让我们理解每个用途。

1. 访问超类的被重写方法

如果超类和子类中都定义了同名方法,子类中的方法将重写超类中的方法。这被称为 方法重写

示例 1:方法重写

class Animal {

// 被重写的方法
public void display(){
System.out.println("I am an animal");
}
}

class Dog extends Animal {

// 重写的方法
@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

在这个例子中,通过创建 Dog 类的对象 dog1,我们可以调用它的方法 printMessage(),然后执行 display() 语句。

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

Java 方法重写示例

如果要调用超类中被重写的方法怎么办?

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

示例 2:使用 super 调用超类方法

class Animal {

// 被重写的方法
public void display(){
System.out.println("I am an animal");
}
}

class Dog extends Animal {

// 重写的方法
@Override
public void display(){
System.out.println("I am a dog");
}

public void printMessage(){

// 这调用了重写的方法
display();

// 这调用了被重写的方法
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();
}
}

输出

我是哺乳动物
我是动物

在这个例子中,我们在超类 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 类的默认或无参构造函数
Animal() {
System.out.println("I am an animal");
}
}

class Dog extends Animal {

// Dog 类的默认或无参构造函数
Dog() {

// 调用超类的默认构造函数
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 {

// 默认或无参构造函数
Animal() {
System.out.println("I am an animal");
}

// 带参数构造函数
Animal(String type) {
System.out.println("Type: "+type);
}
}

class Dog extends Animal {

// 默认构造函数
Dog() {

// 调用超类的带参数构造函数
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

编译器可以自动调用无参构造函数。然而,它不能调用带参数的构造函数。

如果需要调用带参数的构造函数,我们需要在子类构造函数中显式定义它。

super 在调用带参数构造函数时的工作原理。

请注意,在上面的例子中,我们

显式调用了带参数的构造函数 super("Animal")。在这种情况下,编译器不会调用超类的默认构造函数。