super 是子类访问父类被隐藏/覆盖成员的唯一显式引用,三大核心场景:
super(...) 必须置于子类构造器第一行super.method() 解决方法覆盖后仍需复用父逻辑super.field 穿透字段遮蔽class Parent {
Parent() { System.out.println("Parent()"); }
Parent(int v) { System.out.println("Parent(int): " + v); }
}
class Child extends Parent {
Child() {
// 编译器自动插入 super(); 调用无参构造器
System.out.println("Child()");
}
Child(String s) {
super(42); // 显式调用父类有参构造器,必须首行
System.out.println("Child(String): " + s);
}
}
执行 new Child("test") 输出:
Parent(int): 42 Child(String): test
若父类仅提供有参构造器,子类必须显式 super(...),否则编译报错。
class Demo {
Demo() { this(1); } // 调用本类另一构造器
Demo(int x) { super(); } // 编译错误!this() 与 super() 不能共存
}
原因:构造器调用链必须单一入口。this(...) 委托本类构造器,最终仍会由链尾构造器调用 super(...)。JVM 规范要求每条构造器路径仅能调用一次父类构造器,且必须在所有实例字段初始化前完成。
class Recursive {
int value;
Recursive() { this(10); }
Recursive(int v) {
this.value = v;
System.out.println("value=" + value);
}
}
内存分配时序:
new Recursive() → 在堆分配对象内存,value 默认 0this(10) → 同一内存地址,执行 Recursive(int)value = 10 覆盖默认值关键点:整个链共享同一块内存,无重复分配。字段初始化顺序:父类静态 → 子类静态 → 父类实例字段/初始化块 → 父类构造器 → 子类实例字段/初始化块 → 子类构造器。
class Animal {
void speak() { System.out.println("Animal sound"); }
}
class Cat extends Animal {
@Override
void speak() {
super.speak(); // 显式调用父类实现
System.out.println("Meow");
}
void test() {
Animal a = new Cat();
a.speak(); // 多态:输出 Animal sound + Meow
super.speak(); // 静态绑定:仅输出 Animal sound
}
}
super.speak() 是非虚调用,编译期绑定至 Animal.speak(),不受运行时类型影响super 复用通用逻辑class Base { int x = 1; }
class Derived extends Base {
int x = 2; // 遮蔽而非覆盖
void print() {
System.out.println("this.x=" + this.x); // 2
System.out.println("super.x=" + super.x); // 1
System.out.println("((Base)this).x=" + ((Base)this).x); // 1,强制转型同理
}
}
字段无多态,super.x 是访问父类实例字段的唯一标准方式。
super() 以明确意图