super
在 Java 中,super 关键字用于访问和调用父类(超类)的成员,它主要有两个用途:

- 调用父类的构造方法:
super()或super(参数) - 调用父类的成员方法或成员变量:
super.方法名()或super.变量名
我们重点讨论第二种,即调用父类的方法。
调用父类的普通方法(最常用)
当子类重写了(overrode)父类的方法,但又想在该重写的方法中执行父类原来的方法逻辑时,就必须使用 super。
场景: 子类扩展了父类的功能,但希望在父类原有功能的基础上增加新的操作。
语法:
super.父类方法名(参数列表);

代码示例:
// 父类
class Animal {
public void eat() {
System.out.println("Animal is eating.");
}
public void sleep() {
System.out.println("Animal is sleeping.");
}
}
// 子类
class Dog extends Animal {
// Dog 类有自己的 eat() 方法,重写了父类的方法
@Override
public void eat() {
// 首先调用父类原有的 eat() 方法
super.eat();
// 然后添加 Dog 特有的行为
System.out.println("Dog is eating bones.");
}
// Dog 类想使用父类的 sleep() 方法,可以不重写,直接调用。
// 但如果想调用,也可以显式使用 super,虽然不常见。
public void performSleep() {
super.sleep(); // 显式调用父类的 sleep
}
}
public class Main {
public static void main(String[] args) {
Dog myDog = new Dog();
// 调用 Dog 重写的 eat() 方法
// 输出:
// Animal is eating.
// Dog is eating bones.
myDog.eat();
// 调用从父类继承来的 sleep() 方法
// 输出:
// Animal is sleeping.
myDog.sleep();
// 调用 performSleep() 方法,它内部使用 super.sleep()
// 输出:
// Animal is sleeping.
myDog.performSleep();
}
}
分析:
在 Dog 类的 eat() 方法中,我们通过 super.eat() 调用了 Animal 类的 eat() 方法,这允许我们保留父类的核心逻辑,然后在此基础上添加子类特有的行为,这是一种非常常见的代码复用方式。
调用父类的构造方法
这是一个特殊的场景,虽然它不是“方法”,但至关重要,子类在创建对象时,必须先调用父类的构造方法来初始化从父类继承来的成员。
语法:
必须在子类构造方法的第一行使用 super(参数列表); 来调用父类的构造方法。

如果没有显式调用:
如果子类构造方法中没有 super() 语句,Java 编译器会自动在第一行插入一个对父类无参构造方法 super() 的调用,如果父类没有无参构造方法,就会导致编译错误。
代码示例:
// 父类
class Person {
private String name;
// 父类的无参构造方法
public Person() {
this.name = "Unknown";
System.out.println("Person's no-arg constructor is called.");
}
// 父类的带参构造方法
public Person(String name) {
this.name = name;
System.out.println("Person's constructor with name is called.");
}
}
// 子类
class Student extends Person {
private int studentId;
// 子类的构造方法1:调用父类的无参构造方法
public Student() {
// super(); // 这一行是隐式存在的,可以不写
System.out.println("Student's no-arg constructor is called.");
}
// 子类的构造方法2:调用父类的带参构造方法
public Student(String name, int studentId) {
// 必须在第一行显式调用
super(name);
this.studentId = studentId;
System.out.println("Student's constructor with name and id is called.");
}
}
public class Main {
public static void main(String[] args) {
System.out.println("--- Creating Student with no args ---");
Student s1 = new Student();
// 输出:
// Person's no-arg constructor is called.
// Student's no-arg constructor is called.
System.out.println("\n--- Creating Student with args ---");
Student s2 = new Student("Alice", 101);
// 输出:
// Person's constructor with name is called.
// Student's constructor with name and id is called.
}
}
特殊情况:不能使用 super 的情况
如果子类没有重写父类的方法,那么子类对象可以直接调用父类的方法,无需使用 super,使用 super 是可以的,但不是必须的。
class Vehicle {
public void start() {
System.out.println("Vehicle is starting...");
}
}
class Car extends Vehicle {
// Car 没有重写 start() 方法
}
public class Main {
public static void main(String[] args) {
Car myCar = new Car();
// 直接调用,因为 Car 没有自己的 start() 方法
myCar.start(); // 输出: Vehicle is starting...
// 使用 super 调用也是可以的,效果一样
myCar.super.start(); // 语法错误!super 不能用在实例方法中直接这样用
// 正确的用法是在 Car 的某个方法内部使用 super.start()
}
}
注意: myCar.super.start() 这种写法是错误的。super 只能在子类的方法内部使用,用来指代父类的版本。
| 调用场景 | 语法 | 说明 |
|---|---|---|
| 子类重写父类方法,并希望调用父类版本 | super.父类方法名(); |
最常用的场景,用于在扩展功能时保留原有逻辑。 |
| 在子类构造方法中初始化父类部分 | super(参数列表); |
必须在子类构造方法的第一行调用父类的构造方法,如果不写,默认调用 super()。 |
| 子类直接使用父类未重写的方法 | 方法名(); 或 super.方法名(); |
无需 super,直接调用即可,使用 super 是多余的,但语法正确(在方法内部)。 |
关键点
super关键字:是连接子类与父类的桥梁。- 方法重写:是使用
super调用父类方法的主要原因。 - 构造方法链:
super()在构造方法中的调用是强制性的(隐式或显式),它确保了对象从父类到子类的正确初始化顺序。 - 访问权限:只能调用
public或protected的父类方法,如果父类方法是private的,它对子类是不可见的,也就无法通过super调用。
