在本教程中,我们将借助示例学习Java中的super关键字。
Java中的super关键字在子类中用于访问父类成员(属性,构造函数和方法)。
在学习super关键字之前,请确保已经了解Java继承。
调用子类中重写的父类的方法。
如果超类(superclass)和子类(subclass)都有同名的属性,则访问超类的属性(字段)。
从子类构造函数显式地调用超类无参数化构造函数或参数化构造函数。
下面让我们了解所有这些用途。
如果在超类和子类中都定义了相同名称的方法,则子类中的方法将覆盖超类中的方法。这称为方法重写。
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()。
如果必须调用超类的重写方法怎么办?
如果需要调用超类Animal的重载方法display(),则使用super.display()。
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关键字来访问超类的属性。
class Animal { protected String type="动物"; } class Dog extends Animal { public String type="哺乳动物"; public void printType() { System.out.println("我是 " + type); System.out.println("我是一只 " + super.type); } } class Main { public static void main(String[] args) { Dog dog1 = new Dog(); dog1.printType(); } }
输出:
我是哺乳动物 我是一只动物
在这个实例中,我们在超类Animal和子类Dog中定义了相同的实例字段类型。
然后我们创建了Dog类的对象dog1。然后,使用此对象调用printType()方法。
在printType()函数内部,
type - 指的是子类Dog的属性。
super.type - 指超类Animal的属性。
因此,System.out.println("我是 " + type);输出 “我是哺乳动物”,并且,System.out.println("我是一只 " + super.type);打印输出“我是一只动物”。
众所周知,创建类的对象时,将自动调用其默认构造函数。
要从子类构造函数中显式调用超类构造函数,我们使用super()。这是super关键字的一种特殊形式。
注意: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()语句调用超类的构造函数并执行其中的语句。因此,我们得到的结果“I am an animal”。
然后,程序流返回到子类构造函数并执行其余语句。 因此,打印输出“I am a dog”。
但是,不是必须使用super()。 即使在子类构造函数中没有使用super(),编译器也会隐式调用超类的默认构造函数。
那么,如果编译器自动调用super(),为什么还要显式它,而使用冗余代码呢?
如果必须从子类构造函数中调用超类的参数化构造函数(带有参数的构造函数),则必须显式地使用它。
带参数的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("Animal");
请注意,在上面的示例中,我们使用了super("Animal"),显式地调用参数化构造函数。在这种情况下,编译器不会调用超类的默认构造函数。