方法重写、Override 与 super | JavaSE

方法重写、Override 与 super

一、学习目标

学完本章,你应该能够:

  • 能够解释继承后成员访问的“就近原则”。
  • 能够区分局部变量、当前对象成员和父类成员。
  • 能够正确使用 this.成员super.成员
  • 能够解释什么是方法重写(Method Overriding)。
  • 能够区分方法重写(Overriding)和方法重载(Overloading)。
  • 能够正确使用 @Override
  • 能够判断一个方法是否构成合法重写。
  • 能够掌握重写时的访问权限与返回值基本规则。
  • 能够解释为什么 private 方法不属于真正意义上的重写。
  • 能够解释 static 方法为什么属于隐藏(Hiding),而不是实例方法重写。
  • 能够使用 super.父类方法() 调用父类原实现。
  • 能够重写 Object.toString() 改善对象输出。

二、核心知识

2.1 继承以后可能出现同名成员

假设父类:

public class Fu {

    String name = "父类name";

    public void run() {
        System.out.println("父类run");
    }
}

子类:

public class Zi extends Fu {

    String name = "子类name";

    public void run() {
        System.out.println("子类run");
    }
}

此时:

Fu 有 name
Zi 也有 name

Fu 有 run()
Zi 也有 run()

那么在子类中直接写:

name
run()

到底使用哪个?

这就需要理解:

继承后的成员查找与就近原则。


2.2 成员访问的就近原则

例如:

class Fu {

    String name = "fu";
}

class Zi extends Fu {

    String name = "zi";

    public void show() {

        String name = "local";

        System.out.println(name);
    }
}

这里存在三个:

局部变量 name
子类成员变量 name
父类成员变量 name

简单写:

name

首先找到距离当前位置最近的局部变量。

因此:

System.out.println(name);

得到:

local

可以建立基本查找思路:

当前局部范围
     ↓
当前类成员
     ↓
父类中可访问成员

这就是原课程所说的:

就近原则。


2.3 this.成员:当前对象成员

如果希望跳过局部变量:

String name = "local";

访问当前对象自己的成员:

this.name

例如:

class Zi extends Fu {

    String name = "zi";

    public void show() {

        String name = "local";

        System.out.println(name);
        System.out.println(this.name);
    }
}

结果分别对应:

name
    ↓
局部变量

this.name
    ↓
当前 Zi 对象的成员变量

所以:

this

继续表示:

当前对象。


2.4 super.成员:父类视角成员

如果父类和子类存在同名成员:

class Fu {

    String name = "fu";
}

class Zi extends Fu {

    String name = "zi";
}

子类中:

this.name

表示:

当前对象中按照 Zi 当前类成员解析的 name

而:

super.name

表示:

按父类成员关系访问 name

例如:

public void show() {

    String name = "local";

    System.out.println(name);
    System.out.println(this.name);
    System.out.println(super.name);
}

分别对应:

local
zi
fu

因此可以建立一个非常重要的对比:

name
    → 就近查找

this.name
    → 当前对象 / 当前类视角成员

super.name
    → 父类视角成员

2.5 super 不是“父类对象变量”

初学者很容易把:

super

想象成:

一个单独保存父类对象地址的变量

不应该这样理解。

在当前 Java 语境中,更合适的理解是:

super 允许在子类实例上下文中明确引用父类成员或父类实现。

例如:

super.run();

表示:

调用父类版本的 run()

它不是:

Fu super = ...

这样的普通引用变量。


2.6 为什么需要方法重写

假设:

public class Animal {

    public void cry() {
        System.out.println("动物会叫");
    }
}

子类:

public class Cat extends Animal {
}

那么:

Cat cat = new Cat();

cat.cry();

会使用父类提供的:

动物会叫

但是猫真正应该:

喵喵喵

狗应该:

汪汪汪

父类虽然提供了公共行为:

cry()

但父类的默认实现无法满足所有具体子类。

这时就需要:

方法重写(Method Overriding)。


2.7 什么是方法重写

方法重写可以先这样定义:

子类针对从父类继承而来的实例方法,提供符合重写规则的新实现。

例如父类:

public class Animal {

    public void cry() {
        System.out.println("动物会叫");
    }
}

子类:

public class Cat extends Animal {

    @Override
    public void cry() {
        System.out.println("喵喵喵");
    }
}

此时:

Cat cat = new Cat();

cat.cry();

执行的是:

Cat 中重新定义的 cry()

这就是重写。


2.8 Override 与 Overload 不要混淆

前面已经学习:

方法重载(Overloading)

现在学习:

方法重写(Overriding)

二者不是同一个概念。

| 对比 | Overloading 重载 | Overriding 重写 | | ------------ | ---------------------- | ------------------------- | | 典型位置 | 同一个类中即可 | 父子类继承关系 | | 方法名 | 相同 | 相同 | | 参数列表 | 必须不同 | 必须满足相同签名/重写关系 | | 目标 | 同一个功能支持不同参数 | 子类修改父类行为 | | 是否依赖继承 | 不需要 | 需要 |

例如:

public void print(int value) {
}

public void print(String value) {
}

这是:

重载

而:

class Animal {

    public void cry() {
    }
}

class Cat extends Animal {

    @Override
    public void cry() {
    }
}

这是:

重写

口诀可以辅助记忆:

重载:
同名不同参

重写:
父子类中重新实现继承来的实例方法

但最终还是应该理解语义,而不是只背口诀。


2.9 @Override 是什么

推荐在重写方法上使用:

@Override

例如:

@Override
public void cry() {
    System.out.println("喵喵喵");
}

@Override 是一个注解。

它的重要作用之一是:

告诉编译器:我认为这里正在重写一个父类型的方法,请帮我检查。

假设不小心写错:

@Override
public void cyr() {
}

父类并没有:

cyr()

编译器就会直接提示问题。

这比没有 @Override 时悄悄创建一个新方法更加安全。

所以实际开发中:

只要是在重写方法,通常就应该写 @Override


2.10 重写要求:方法签名必须匹配

最基础的重写需要保证:

方法名匹配
参数列表匹配

例如父类:

public void cry() {
}

子类:

@Override
public void cry() {
}

构成重写。

但是:

public void cry(String message) {
}

不是对:

cry()

的重写。

它参数列表不同。

更接近:

新增了一个重载方法。


2.11 重写不能降低访问权限

父类:

public void cry() {
}

子类不能:

@Override
protected void cry() {
}

因为访问权限被缩小。

如果父类:

protected void cry() {
}

子类可以:

@Override
public void cry() {
}

也就是:

子类重写方法不能比父类被重写方法拥有更严格的访问限制。

初学阶段可以理解成:

父类 public
    ↓
子类只能 public

父类 protected
    ↓
子类可以 protected / public

2.12 为什么不能缩小访问权限

假设:

class Animal {

    public void cry() {
    }
}

外部代码本来认为:

所有 Animal 都公开提供 cry()

如果子类:

class Cat extends Animal {

    private void cry() {
    }
}

突然把这一公开能力隐藏起来,就会破坏:

Cat 是一种 Animal

所承诺的公共行为。

所以 Java 不允许重写方法降低访问权限。


2.13 返回值类型规则

原始课程把规则简化为:

返回值类型必须相同,或者“范围更小”。

对于引用类型,更专业的名称叫:

协变返回类型(Covariant Return Type)

例如:

class Animal {
}

class Dog extends Animal {
}

父类方法:

class Factory {

    public Animal create() {
        return new Animal();
    }
}

子类:

class DogFactory extends Factory {

    @Override
    public Dog create() {
        return new Dog();
    }
}

这是合法的。

因为:

Dog

是:

Animal

的子类型。

因此子类重写方法可以返回更加具体的引用类型。


2.14 基本数据类型不能这样随便缩小

不要把:

返回值范围更小

错误理解成:

父类返回 double
子类返回 int

也可以。

例如:

class Parent {

    public double getValue() {
        return 1.0;
    }
}

子类不能:

@Override
public int getValue() {
    return 1;
}

这不构成合法的协变返回。

协变主要针对:

引用类型的子类型关系。


2.15 private 方法不能被真正重写

父类:

class Parent {

    private void test() {
        System.out.println("Parent");
    }
}

子类:

class Child extends Parent {

    public void test() {
        System.out.println("Child");
    }
}

这两个方法虽然:

名称一样
参数一样

Child.test() 并不是从 Java 技术意义上“重写 Parent.test()`。

因为:

Parent.test()

是 private。

子类根本不能继承并访问该方法作为重写目标。

所以:

private 方法不能被真正重写。

如果子类恰好声明同名方法,那是子类自己的新成员。


2.16 static 方法不是实例方法重写

父类:

class Parent {

    public static void test() {
        System.out.println("Parent");
    }
}

子类:

class Child extends Parent {

    public static void test() {
        System.out.println("Child");
    }
}

这不属于实例方法的:

Overriding

而属于:

方法隐藏(Method Hiding)

也就是:

static 方法由类决定
实例方法才参与通常所说的动态方法重写体系

因此:

“静态方法不能被重写”是入门阶段常见的简化表达。

更精确地说:

子类声明相同签名的 static 方法时发生隐藏,而不是实例方法重写。


2.17 final 方法不能被重写

如果父类:

class Parent {

    public final void test() {
        System.out.println("test");
    }
}

子类不能:

@Override
public void test() {
}

因为:

final

已经明确表示:

这个方法不允许子类重新定义实现。

final 会在后面的专章系统学习。

这里先知道它会影响方法重写即可。


2.18 super.方法() 调用父类实现

假设:

class Animal {

    public void cry() {
        System.out.println("动物会叫");
    }
}

子类:

class Cat extends Animal {

    @Override
    public void cry() {
        System.out.println("喵喵喵");
    }
}

在 Cat 中:

cry();

通常对应当前子类重写后的行为。

但如果明确希望调用父类原实现:

super.cry();

例如:

class Cat extends Animal {

    @Override
    public void cry() {
        super.cry();
        System.out.println("猫具体表现为:喵喵喵");
    }
}

于是子类可以:

保留父类一部分行为,再添加自己的扩展。


2.19 重写并不意味着必须彻底抛弃父类实现

有两种常见方式。

完全替换

@Override
public void cry() {
    System.out.println("喵喵喵");
}

完全不调用父类。


在父类基础上扩展

@Override
public void work() {

    super.work();

    System.out.println("执行子类额外工作");
}

具体选哪一种取决于:

子类业务需求。


2.20 super 与 this 的基本对比

| 写法 | 主要含义 | | ---------------- | ---------------------- | | this.xxx | 当前对象的成员 | | super.xxx | 父类视角的成员 | | this.method() | 当前对象的方法调用 | | super.method() | 明确调用父类版本的方法 |

例如:

class Fu {

    String name = "fu";

    public void run() {
        System.out.println("Fu.run");
    }
}
class Zi extends Fu {

    String name = "zi";

    @Override
    public void run() {
        System.out.println("Zi.run");
    }

    public void show() {

        String name = "local";

        System.out.println(name);
        System.out.println(this.name);
        System.out.println(super.name);

        run();
        this.run();
        super.run();
    }
}

这里可以系统训练:

局部
当前对象
父类成员

当前实现
父类实现

之间的关系。


2.21 super 不能在 static 上下文中直接使用

与:

this

类似,super 也是实例继承上下文中的关键字。

例如:

public static void test() {
    // super.run();
}

是不允许的。

因为静态方法不依赖当前实例,自然也没有:

当前对象的父类视角

三、使用方法

3.1 Animal / Cat 重写

父类:

public class Animal {

    public void cry() {
        System.out.println("动物会叫");
    }
}

子类:

public class Cat extends Animal {

    @Override
    public void cry() {
        System.out.println("喵喵喵~~~");
    }
}

测试:

public class Test {

    public static void main(String[] args) {

        Cat cat = new Cat();

        cat.cry();
    }
}

这种场景表达:

Animal 定义共同能力
Cat 给出自己的具体实现

3.2 在父类实现基础上增强

父类:

public class Employee {

    public void work() {
        System.out.println("开始工作");
    }
}

子类:

public class Programmer extends Employee {

    @Override
    public void work() {

        super.work();

        System.out.println("分析需求");
        System.out.println("编写代码");
        System.out.println("运行测试");
    }
}

这种方式表示:

保留父类通用步骤
+
追加子类具体步骤

3.3 使用 super 解决同名成员问题

class Parent {

    String name = "Parent";

    public void show() {
        System.out.println("Parent.show");
    }
}
class Child extends Parent {

    String name = "Child";

    @Override
    public void show() {
        System.out.println("Child.show");
    }

    public void test() {

        String name = "Local";

        System.out.println(name);
        System.out.println(this.name);
        System.out.println(super.name);

        this.show();
        super.show();
    }
}

这是本章非常重要的闭卷代码。

必须能够不运行代码,直接判断每一次访问最终找到哪里。


3.4 重写 Object.toString()

定义:

public class Student {

    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

如果:

Student student = new Student("张三", 20);

System.out.println(student);

没有重写 toString() 时,结果并不适合直接阅读对象业务数据。

可以:

@Override
public String toString() {
    return "Student{" +
            "name='" + name + '\'' +
            ", age=" + age +
            '}';
}

完整:

public class Student {

    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

于是:

System.out.println(student);

能够得到更适合阅读的对象描述。


3.5 为什么 System.out.println(student) 会调用 toString()

当输出一个普通对象时,Java 输出机制最终会获得该对象的字符串表示。

因此:

System.out.println(student);

能够体现对象的:

toString()

结果。

所以实际 Debug 时,经常会给实体类重写:

toString()

方便查看:

对象内部字段值

四、原理与进阶

4.1 方法重写是运行时多态的重要基础

现在先观察:

Cat cat = new Cat();
cat.cry();

调用 Cat 重写后的 cry()

下一阶段学习多态后,会进一步写:

Animal animal = new Cat();
animal.cry();

虽然变量类型是:

Animal

实际运行时仍然可能执行:

Cat.cry()

这就是:

动态方法分派(Dynamic Method Dispatch)

背后的核心现象之一。

所以方法重写不是:

仅仅为了让子类方法“名字一样”。

它是 Java 面向对象运行时多态的重要基础。


4.2 @Override 不是决定重写成立的根本原因

假设:

class Animal {

    public void cry() {
    }
}
class Cat extends Animal {

    public void cry() {
    }
}

即使没有:

@Override

只要符合 Java 重写规则,仍然属于重写。

因此:

@Override

不是:

开启方法重写功能的开关。

它主要用于:

  • 编译器检查;
  • 表达开发者意图;
  • 提高可读性;
  • 降低签名写错风险。

所以推荐始终使用。


4.3 方法重写与字段隐藏不是同一机制

父类:

class Parent {

    String name = "Parent";
}

子类:

class Child extends Parent {

    String name = "Child";
}

这里两个:

name

不是:

“字段重写”。

字段没有实例方法那种运行时重写机制。

这属于字段隐藏/同名成员问题。

因此:

this.name
super.name

和:

this.run()
super.run()

背后的语言机制并不完全相同。

初学阶段先做到:

不把“同名字段”叫做方法重写。


4.4 static 方法隐藏与实例方法重写

父类静态方法:

class Parent {

    public static void test() {
    }
}

子类:

class Child extends Parent {

    public static void test() {
    }
}

这种情况:

Child.test()

隐藏父类同签名 static 方法。

而实例方法:

public void test()

在满足条件时才形成:

Overriding

所以必须建立:

instance method
    ↓
overriding

static method
    ↓
hiding

这个专业术语区别。


4.5 返回值“范围更小”的准确理解

不要只背:

重写返回值可以更小

真正需要理解的是:

对引用返回类型,重写方法可以返回父方法返回类型的子类型。

例如:

Animal
   ↑
Dog

父类:

public Animal create()

子类:

public Dog create()

合法。

这种能力叫:

协变返回类型(Covariant Return Type)

它让子类 API 可以给出更加具体的返回结果。


4.6 throws 也存在重写限制

如果父方法声明受检异常(Checked Exception),子类重写时不能任意扩大受检异常范围。

这一点会涉及:

异常体系
throws
编译时异常

冻结课程将在异常章节系统学习。

所以当前只记住:

方法重写不仅受方法名和参数控制,返回类型、访问权限以及异常声明也存在语言规则。

等学完异常后再回看这条规则会更加清晰。


五、实践应用

5.1 不同动物拥有不同实现

Animal
├── Dog
├── Cat
└── Bird

父类:

public class Animal {

    public void sound() {
        System.out.println("动物发出声音");
    }
}

子类分别重写:

Dog → 汪汪
Cat → 喵喵
Bird → 啾啾

这种设计将:

共同能力名称

统一在父类。

而:

具体行为实现

交给子类。

这就是面向对象中非常重要的:

统一抽象 + 不同实现。


5.2 支付行为的重写

假设:

public class Card {

    public void pay(double money) {
        System.out.println("支付:" + money);
    }
}

金卡:

public class GoldCard extends Card {

    @Override
    public void pay(double money) {
        System.out.println("金卡支付");
        System.out.println("原价:" + money);
        System.out.println("优惠后:" + money * 0.8);
    }
}

这时子类重新定义:

同一个 pay() 行为在金卡对象上的具体规则。

后面学习多态后,会进一步体会这种设计价值。


5.3 toString 在 Debug 中的价值

没有重写:

Student@3a71f4dd

重写后:

Student{name='LingXi', age=21, score=95.0}

调试时后一种明显更容易判断:

  • 字段有没有赋值;
  • 数据是否正确;
  • 哪个对象出了问题。

所以 toString() 是实际开发中最常见的重写案例之一。


六、常见问题

6.1 什么是方法重写?

子类针对父类可被重写的实例方法提供新的实现。


6.2 重写和重载有什么区别?

最核心:

重载:
同名不同参数

重写:
继承体系中对子类已有父类实例方法重新实现

6.3 @Override 必须写吗?

不是重写成立的必要条件。

但是:

强烈推荐写。

因为它可以让编译器帮助检查,并明确表达开发者意图。


6.4 方法名一样就是重写吗?

不是。

还必须满足:

  • 继承关系;
  • 方法签名规则;
  • 可访问性;
  • 返回类型等要求。

6.5 参数列表不同还是重写吗?

通常不是。

例如:

cry()
cry(String message)

更接近重载关系。


6.6 子类能把 public 方法重写成 protected 吗?

不能。

这会降低访问权限。


6.7 protected 方法能重写成 public 吗?

可以。

因为没有缩小可访问范围。


6.8 private 方法能被重写吗?

不能形成 Java 技术意义上的真正重写。

父类 private 方法对子类不是一个可重写的继承成员。


6.9 static 方法能重写吗?

严格来说:

static 同签名方法属于隐藏(Hiding),不是实例方法重写。


6.10 final 方法能重写吗?

不能。

final 表示不允许子类重写该方法。


6.11 返回值必须完全一样吗?

基本类型等场景要求严格匹配。

对于引用类型:

可以存在协变返回类型。

即子类返回更加具体的子类型。


6.12 super.method() 有什么作用?

在子类中明确调用父类版本的方法。


6.13 this.method() 和 super.method() 有什么区别?

this.method()

从当前对象角度进行方法调用。

super.method()

明确选择父类版本。


6.14 super(...) 为什么这里不讲?

因为:

super(...)

是父类构造器调用语法。

冻结课程专门安排到:

02-09 子类构造器与 this(...) / super(...)

本章只学习:

super.成员
super.方法()

6.15 为什么重写 toString()?

Object 默认字符串通常不够直观。

重写以后可以返回:

更适合开发者和用户阅读的对象状态描述。


七、练习与验收

7.1 知识问答

  1. 什么叫继承后的就近原则?
  2. 局部变量、子类字段、父类字段同名时如何区分?
  3. this.name 表示什么?
  4. super.name 表示什么?
  5. super 是一个普通父类对象引用变量吗?
  6. 什么是方法重写?
  7. 为什么需要方法重写?
  8. 方法重写和方法重载有什么本质区别?
  9. @Override 有什么作用?
  10. 不写 @Override 是否一定不构成重写?
  11. 重写方法的参数列表有什么要求?
  12. 为什么重写不能降低访问权限?
  13. 引用类型返回值为什么允许协变?
  14. private 方法为什么不能真正重写?
  15. static 方法为什么不是实例方法重写?
  16. static 同签名方法的专业名称是什么?
  17. final 方法为什么不能被重写?
  18. super.method() 有什么意义?
  19. 为什么重写是后续多态的重要基础?
  20. 为什么经常重写 Object.toString()

7.2 代码阅读

不运行下面代码:

class Fu {

    String name = "fu";

    public void run() {
        System.out.println("Fu.run");
    }
}

class Zi extends Fu {

    String name = "zi";

    @Override
    public void run() {
        System.out.println("Zi.run");
    }

    public void show() {

        String name = "local";

        System.out.println(name);
        System.out.println(this.name);
        System.out.println(super.name);

        run();
        this.run();
        super.run();
    }
}

要求依次写出:

  1. 三次 name 最终来自哪里。
  2. 三次 run() 最终调用哪里。
  3. 每一次解析的理由。
  4. 哪些体现就近原则。
  5. 哪些体现 this
  6. 哪些体现 super

阅读:

class Parent {

    public Number create() {
        return 1;
    }
}

class Child extends Parent {

    @Override
    public Integer create() {
        return 10;
    }
}

回答:

  1. 是否属于合法重写?
  2. 为什么返回类型不完全相同仍可能合法?
  3. IntegerNumber 存在什么类型关系?
  4. 这种返回规则叫什么?

7.3 手写代码

任务一:Animal 重写

设计:

Animal
Dog
Cat

要求:

Animal:
cry()

Dog:
重写 cry()

Cat:
重写 cry()

每个重写方法必须写:

@Override

然后说明:

为什么这里是重写而不是重载?


任务二:父类增强

设计:

Employee
Programmer

父类:

work()

打印通用工作准备。

子类重写:

work()

要求:

  1. 先调用 super.work()
  2. 再打印程序员自己的工作步骤。
  3. 解释为什么需要 super.work()

任务三:toString

创建:

Student

包含:

name
age
score

要求:

  1. 不重写 toString,先观察默认结果。
  2. 手写 @Override toString()
  3. 再次输出对象。
  4. 比较两种结果。
  5. 说明为什么第二种更适合 Debug。

7.4 Debug

下面代码有什么问题?

class Parent {

    public void test() {
    }
}

class Child extends Parent {

    @Override
    private void test() {
    }
}

要求:

  1. 判断问题是否出在方法名。
  2. 判断问题是否出在参数。
  3. 判断真正违反哪条重写规则。
  4. 修复代码。

下面代码:

class Parent {

    public static void test() {
        System.out.println("Parent");
    }
}

class Child extends Parent {

    public static void test() {
        System.out.println("Child");
    }
}

回答:

  1. 这是不是普通实例方法重写?
  2. 正确术语是什么?
  3. 为什么 static 方法与实例重写机制不同?

下面代码:

class Parent {

    private void run() {
    }
}

class Child extends Parent {

    @Override
    public void run() {
    }
}

要求:

  1. 判断 @Override 是否成立。
  2. 为什么?
  3. 删除 @OverrideChild.run() 是什么性质的方法?

7.5 综合训练

设计一个支付卡体系:

Card
├── GoldCard
└── SilverCard

父类包含:

owner
balance
pay(double money)

要求:

  • GoldCard 重写 pay(),使用一种优惠规则;
  • SilverCard 重写 pay(),使用另一种优惠规则;
  • 重写时全部使用 @Override
  • 必要时使用 super 复用父类通用逻辑;
  • 暂时不使用多态变量;
  • 不提前使用抽象类或接口。

完成后回答:

为什么 pay() 很适合设计成父类公共行为并由不同子类重写?

7.6 本章验收

关闭资料与 AI 自动补全,检查自己能否:

  • [ ] 手写 this.namesuper.name
  • [ ] 解释成员访问就近原则。
  • [ ] 不运行代码分析 local / this / super 三种成员来源。
  • [ ] 准确定义方法重写。
  • [ ] 区分 Overloading 与 Overriding。
  • [ ] 正确使用 @Override
  • [ ] 判断参数不同时为什么不是重写。
  • [ ] 判断重写为什么不能降低访问权限。
  • [ ] 解释协变返回类型。
  • [ ] 解释 private 方法为什么不能真正重写。
  • [ ] 解释 static 方法隐藏。
  • [ ] 知道 final 方法不能重写。
  • [ ] 手写 super.method()
  • [ ] 重写 Object.toString()
  • [ ] 解释方法重写为什么为多态打下基础。

如果你只是知道:

@Override

可以让 IDEA 自动生成一个方法,却无法解释:

为什么这个方法属于重写、
编译器到底在检查什么、
this 与 super 分别指向哪一层语义,

那么本章仍然没有真正掌握。