Java super 关键字
Java 中的 super
关键字用于在子类中访问父类成员(属性、构造方法和方法)。在本教程中,我们将通过示例了解 Java 中的 super 关键字的用法。
Java 中的 super
关键字用于在子类中访问父类成员(属性、构造方法和方法)。在本教程中,我们将通过示例学习 Java 中的 super 关键字。
在我们学习 super
关键字之前,请确保了解了 Java 继承的概念。
super 关键字作用
- 在子类中调用被覆盖的父类的方法。
- 如果父类和子类都具有同名的属性,则访问父类的属性(字段)。
- 从子类构造方法中显式调用父类的构造方法。
让我们了解这些用途中的每一个。
访问父类的重写方法
如果在子类中定义了和父类同名方法,则子类中的方法会覆盖父类中的方法。这称为方法覆盖。
示例 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();
}
}
输出
这是一只狗
如果必须调用父类的重写方法怎么办?
我们使用 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();
}
}
输出
这是一只狗
这是一只动物
下图展示了上面例子的调用流程:
访问父类的属性
父类和子类可以具有相同名称的属性。我们使用 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()
语句调用父类的构造方法并执行其中的语句。因此,先打印 这是一只动物
。
然后程序流程返回到子类构造方法并执行剩余的语句。因此,再打印 这是一只狗
。
但是,使用 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("动物")
调用了带参数的构造方法。在这种情况下,编译器不会调用父类的默认构造方法。