【Java SE】super 关键字详解
super 关键字详解
- super 的本质与作用
- super 的三种用法
- a) 调用父类构造方法
- b) 访问父类属性
- b) 调用父类方法
- 深入理解 super 的查找机制(查找路径规则)
- super 与 this 的完整对比
- 常见陷阱
- 陷阱1:在静态方法中使用 super
- 陷阱2:super 与多态的误解
- 陷阱3:构造方法中 this 和 super 的冲突
super 的本质与作用
super是 Java 中的一个引用变量,用于直接引用父类对象。它不是一个独立的对象,而是当前对象中对父类部分的引用。
核心作用:
- 解决子类与父类中成员(属性、方法)的命名冲突
- 显式调用父类的构造方法
- 实现父类功能的复用与扩展
super 的三种用法
| 用法 | 示例 | 说明 |
|---|---|---|
| 调用父类构造方法 | super(参数) | 必须在子类构造方法第一行 |
| 访问父类属性 | super.属性名 | 当子类属性隐藏父类属性时使用 |
| 调用父类方法 | super.方法名() | 当子类重写父类方法时使用 |
a) 调用父类构造方法
子类构造方法需要初始化继承自父类的属性,或调用父类特定的构造逻辑。
语法规则:
- 必须写在子类构造方法的第一行
- 如果子类构造方法中没有显式调用
super(...),编译器会自动插入super()(调用父类的无参构造) - 如果父类没有无参构造,子类必须显式调用父类的带参构造
classAnimal{Stringname;intage;// 父类带参构造publicAnimal(Stringname,intage){this.name=name;this.age=age;System.out.println("父类构造被调用");}publicAnimal(){System.out.println("父类无参构造被调用");}}classDogextendsAnimal{Stringbreed;// 显式调用父类带参构造publicDog(Stringname,intage,Stringbreed){super(name,age);// 必须第一行this.breed=breed;}// 默认调用父类无参构造publicDog(){// 隐式调用 super()System.out.println("子类构造被调用");}}执行顺序验证:
publicclassTest{publicstaticvoidmain(String[]args){Dogdog1=newDog("旺财",3,"金毛");System.out.println("---");Dogdog2=newDog();}}输出:
父类构造被调用 --- 父类无参构造被调用 子类构造被调用b) 访问父类属性
子类定义了与父类同名的属性(属性隐藏),需要访问父类的属性时。
classParent{Stringname="父类名字";StringparentOnly="父类特有属性";}classChildextendsParent{Stringname="子类名字";// 隐藏了父类的 namevoidprintNames(){System.out.println("直接访问 name: "+name);// 子类System.out.println("this.name: "+this.name);// 子类System.out.println("super.name: "+super.name);// 父类System.out.println("父类特有属性: "+parentOnly);// 可直接访问}}注意事项:
super不能跨级访问祖父类的属性(只能直接访问父类)- 如果父类属性是
private,则super也无法直接访问
b) 调用父类方法
- 子类重写了父类方法,但仍需使用父类的原有功能
- 在子类方法中扩展父类方法的功能
classCalculator{protectedintadd(inta,intb){returna+b;}protectedvoidshowInfo(){System.out.println("这是计算器类");}}classAdvCalculatorextendsCalculator{// 重写并扩展父类方法@Overrideprotectedintadd(inta,intb){// 先调用父类方法,再添加额外逻辑intresult=super.add(a,b);System.out.println("计算结果: "+result);returnresult;}@OverrideprotectedvoidshowInfo(){super.showInfo();// 复用父类逻辑System.out.println("这是高级计算器类");}}输出验证:
publicclassTest{publicstaticvoidmain(String[]args){AdvCalculatorcalc=newAdvCalculator();calc.add(3,5);calc.showInfo();}}输出:
计算结果: 8 这是计算器类 这是高级计算器类深入理解 super 的查找机制(查找路径规则)
classGrandParent{voidmethod(){System.out.println("GrandParent");}}classParentextendsGrandParent{voidmethod(){System.out.println("Parent");}}classChildextendsParent{voidmethod(){System.out.println("Child");}voidtest(){// super 从直接父类开始向上查找super.method();// 调用 Parent 的 method// 无法直接调用 GrandParent 的 method(需要间接方式)}voidcallGrandParent(){// 间接调用祖父类的方法((GrandParent)this).method();// 注意:这是运行时绑定,实际仍是调用子类的// 正确方式:通过父类的 supernewParent().method();// 创建父类实例调用}}重要理解:
super不是独立对象,不能写super.super.method()super遵循静态绑定(编译时确定调用哪个类的方法)- 当调用
super.method()时,直接查找父类的方法定义,不会向下查找
super 与 this 的完整对比
| 比较维度 | super | this |
|---|---|---|
| 查找起点 | 从父类开始向上查找 | 从当前类开始向上查找 |
| 适用范围 | 父类构造、父类成员 | 本类构造、本类成员 |
| 独立性 | 不是独立对象,只是引用 | 当前对象的引用 |
| 在构造方法中 | 调用父类构造,必须在第一行 | 调用本类其他构造,必须在第一行 |
| 能否同时使用 | 不能同时使用(都需在第一行) | 不能同时使用(都需在第一行) |
| 静态上下文中 | 不能使用 | 不能使用 |
| 访问权限 | 受父类访问修饰符限制 | 受本类访问修饰符限制 |
代码演示:
classBase{Stringname="Base";voidshow(){System.out.println("Base show");}}classDerivedextendsBase{Stringname="Derived";voidshow(){System.out.println("Derived show");}voiddemonstrate(){// this 和 super 的对比System.out.println(this.name);// DerivedSystem.out.println(super.name);// Basethis.show();// Derived showsuper.show();// Base show// 类型比较System.out.println(thisinstanceofBase);// true// System.out.println(super instanceof Base); // 编译错误,super不能用于instanceof}}常见陷阱
陷阱1:在静态方法中使用 super
classTest{staticvoidstaticMethod(){// super.toString(); // 编译错误!不能在静态上下文使用 super}publicstaticvoidmain(String[]args){// 不能在静态上下文使用 super}}陷阱2:super 与多态的误解
classParent{voidmethod(){System.out.println("Parent");}}classChildextendsParent{voidmethod(){System.out.println("Child");}voidcallParent(){// 即使子类重写了方法,super.method() 一定调用父类的super.method();// 输出 "Parent"}}陷阱3:构造方法中 this 和 super 的冲突
classChildextendsParent{Child(){// this("hello"); // 如果调用本类其他构造// super(); // 就不能同时调用 super()// 两者只能选其一}Child(Strings){super();// 必须第一行}}