02_super关键字与父类访问
一、super 关键字的基本概念
super是 Java 中的一个特殊关键字,与this类似,但其作用是引用当前对象的父类实例。通过super,子类可以访问父类中被隐藏的成员(属性、方法)或调用父类的构造器,是连接子类与父类的重要桥梁。
super的核心作用是明确指定访问父类的成员,尤其在子类与父类存在同名成员时,用于区分两者的成员,避免歧义。

二、super 关键字的核心使用场景
2.1 场景 1:访问父类的属性(super. 属性名)
当子类的属性与父类的属性同名时,使用super.属性名明确访问父类的属性,避免被子类的同名属性 “隐藏”。
示例代码:
// 父类
class Animal {
protected String name = "动物"; // 父类属性
}
// 子类
class Dog extends Animal {
private String name = "狗"; // 子类属性(与父类同名)
public void showNames() {
System.out.println("子类的name:" + name); // 访问子类属性 → 输出“狗”
System.out.println("父类的name:" + super.name); // 访问父类属性 → 输出“动物”
}
}
// 测试
public class Test {
public static void main(String[] args) {
Dog dog = new Dog();
dog.showNames();
}
}
说明:
- 子类的name属性会 “隐藏” 父类的同名属性,直接使用name访问的是子类自己的属性。
- super.name强制访问父类的name属性,解决同名属性的冲突问题。
2.2 场景 2:调用父类的方法(super. 方法名 (参数))
当子类重写了父类的方法后,使用super.方法名(参数)可以调用父类中被重写的方法,而非子类的重写版本。
示例代码:
// 父类
class Animal {
public void eat() { // 父类方法
System.out.println("动物在吃东西");
}
}
// 子类
class Dog extends Animal {
// 重写父类的eat()方法
@Override
public void eat() {
System.out.println("狗在吃骨头");
}
public void showParentEat() {
super.eat(); // 调用父类被重写的eat()方法 → 输出“动物在吃东西”
}
}
// 测试
public class Test {
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat(); // 调用子类重写的方法 → 输出“狗在吃骨头”
dog.showParentEat(); // 调用父类的方法 → 输出“动物在吃东西”
}
}
说明:
- 子类重写父类方法后,默认情况下调用的是子类的版本。
- super.eat()强制调用父类的eat()方法,保留父类的原始逻辑。
2.3 场景 3:调用父类的构造器(super (参数))
子类的构造器中,使用super(参数列表)可以调用父类的指定构造器,用于初始化父类的成员,是子类构造器中常见的操作。
示例代码:
// 父类
class Person {
protected String name;
protected int age;
// 父类的有参构造器
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
// 子类
class Student extends Person {
private String school;
// 子类的构造器
public Student(String name, int age, String school) {
// 调用父类的有参构造器,初始化name和age
super(name, age);
this.school = school; // 初始化子类自己的属性
}
public void showInfo() {
System.out.println("姓名:" + name + ",年龄:" + age + ",学校:" + school);
}
}
// 测试
public class Test {
public static void main(String[] args) {
Student student = new Student("张三", 18, "一中");
student.showInfo(); // 输出“姓名:张三,年龄:18,学校:一中”
}
}
说明:
- 子类构造器中,super(name, age)调用父类的Person(String, int)构造器,完成父类属性的初始化。
- 注意:super(...)必须放在子类构造器的第一行(否则编译错误),确保父类成员先于子类成员初始化。
2.4 场景 4:默认调用父类的无参构造器
如果子类构造器中没有显式使用super(...),编译器会自动添加super(),即默认调用父类的无参构造器。
示例代码:
// 父类
class Animal {
// 父类的无参构造器
public Animal() {
System.out.println("父类无参构造器被调用");
}
}
// 子类
class Cat extends Animal {
// 子类构造器(未显式调用super())
public Cat() {
// 编译器自动添加:super();
System.out.println("子类构造器被调用");
}
}
// 测试
public class Test {
public static void main(String[] args) {
Cat cat = new Cat();
// 输出:
// 父类无参构造器被调用
// 子类构造器被调用
}
}
注意事项:
- 若父类没有无参构造器(如只定义了有参构造器),子类构造器中必须显式调用父类的有参构造器(super(参数)),否则编译错误。
错误示例:
// 父类(只有有参构造器,无默认无参构造器)
class Animal {
public Animal(String name) {
// 父类有参构造器
}
}
// 子类(编译错误)
class Cat extends Animal {
public Cat() {
// 错误:父类没有无参构造器,编译器无法自动添加super()
}
}
解决方法(显式调用父类有参构造器):
class Cat extends Animal {
public Cat() {
super("小猫"); // 显式调用父类的有参构造器
}
}
三、super 与 this 的对比
super和this都用于引用对象成员,但作用对象不同,对比如下:
| 关键字 | 引用对象 | 主要用途 | 调用构造器的位置 |
|---|---|---|---|
| this | 当前对象 | 访问当前对象的属性、方法;调用当前类的其他构造器(this(...)) | 必须放在构造器第一行 |
| super | 当前对象的父类实例 | 访问父类的属性、方法;调用父类的构造器(super(...)) | 必须放在构造器第一行 |
注意:同一构造器中,this(...)和super(...)不能同时使用(两者都要求放在第一行,存在冲突)。
四、使用 super 的注意事项
- 只能在非静态方法和构造器中使用:super依赖于具体的对象实例,静态方法中不能使用(静态方法属于类,不关联对象)。
- 不能访问父类的私有成员:父类的private属性和方法对子类完全隐藏,即使使用super也无法访问(需通过父类的public/protected方法间接访问)。
示例:
class Parent {
private int id; // 私有属性
}
class Child extends Parent {
public void test() {
// super.id; // 错误:无法访问父类的private属性
}
}
- 避免过度依赖 super:子类应尽量通过重写父类方法扩展功能,而非频繁使用super调用父类方法,否则会增加子类与父类的耦合度。
五、总结
super关键字是子类访问父类成员的核心工具,主要使用场景包括:
- 访问父类的属性(super.属性名),解决与子类同名属性的冲突。
- 调用父类的方法(super.方法名(参数)),尤其是调用被重写的父类方法。
- 调用父类的构造器(super(参数)),完成父类成员的初始化,是子类构造器的必要操作。
理解super的使用规则,能帮助开发者正确处理子类与父类的继承关系,避免成员访问冲突,确保继承体系的正确性和灵活性。

浙公网安备 33010602011771号