|
|
@@ -166,7 +166,243 @@ class Student extends Car { } // 学生不是汽车的一种 ✗
|
|
|
|
|
|
---
|
|
|
|
|
|
-## 二、随堂练习——学生成绩管理系统(构造方法版)
|
|
|
+### 8. 方法重写(Method Override)
|
|
|
+
|
|
|
+**文件**:`Demo01.java`、`Bird.java`、`Penguin.java`
|
|
|
+
|
|
|
+当子类中出现与父类 **完全相同的方法名、参数列表和返回值类型** 的方法时,称为 **方法重写(Override)**。子类会覆盖父类的方法,默认调用子类的版本。
|
|
|
+
|
|
|
+```java
|
|
|
+// 父类 Animal
|
|
|
+public class Animal {
|
|
|
+ public void eat() {
|
|
|
+ System.out.println("吃......");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 子类 Bird —— 重写父类的 eat() 方法
|
|
|
+public class Bird extends Animal {
|
|
|
+ // @Override 是重写注解(可选),加上后编译器会检查该方法是否真的重写了父类方法
|
|
|
+ // 即使不加 @Override,只要方法签名完全一致,也是重写
|
|
|
+ public void eat() {
|
|
|
+ System.out.println("鸟吃自己的.....");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 子类 Penguin —— 重写父类 Bird 的 fly() 方法
|
|
|
+public class Penguin extends Bird {
|
|
|
+ @Override // 推荐加上,便于阅读和检查
|
|
|
+ public void fly() {
|
|
|
+ System.out.println("我不飞..我肚皮贴着冰面滑......");
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**重写 vs 非重写**:
|
|
|
+| 情况 | 结果 |
|
|
|
+|------|------|
|
|
|
+| 子类方法与父类方法 **签名完全一致** | 重写(Override) |
|
|
|
+| 子类方法与父类方法 **方法名不同** | 子类特有的方法,不是重写 |
|
|
|
+
|
|
|
+**测试效果**:
|
|
|
+```java
|
|
|
+// Test01.java
|
|
|
+public class Test01 {
|
|
|
+ public static void main(String[] args) {
|
|
|
+ Animal animal = new Animal();
|
|
|
+ animal.eat(); // 吃......
|
|
|
+
|
|
|
+ Bird bird = new Bird();
|
|
|
+ bird.eat(); // 鸟吃自己的.....(重写后调用子类版本)
|
|
|
+
|
|
|
+ Penguin p = new Penguin();
|
|
|
+ p.fly(); // 我不飞..我肚皮贴着冰面滑......(重写后调用子类版本)
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+> **注意**:重写发生在 **子类和父类之间**,方法签名必须完全一致(方法名 + 参数列表 + 返回值类型)。重写不是必须加 `@Override` 注解,但建议加上,因为它能让编译器帮助检查是否正确重写。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 9. super 关键字
|
|
|
+
|
|
|
+**文件**:`Granddad.java`、`Dad.java`、`Son.java`、`Test02.java`
|
|
|
+
|
|
|
+`super` 关键字用于在子类中 **引用父类的成员**(方法或属性),主要用在以下场景:
|
|
|
+
|
|
|
+| 使用方式 | 说明 |
|
|
|
+|---------|------|
|
|
|
+| `super.父类方法()` | 调用父类中被重写的方法 |
|
|
|
+| `super.父类属性` | 访问父类中与子类同名的属性 |
|
|
|
+
|
|
|
+**示例:多层链式调用 `super.eat()`**
|
|
|
+
|
|
|
+```java
|
|
|
+// Granddad.java —— 爷爷类(顶层父类)
|
|
|
+public class Granddad {
|
|
|
+ public void eat() {
|
|
|
+ System.out.println("爷爷爱喝酒....");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Dad.java —— 父亲类(继承 Granddad)
|
|
|
+public class Dad extends Granddad {
|
|
|
+ public void eat() {
|
|
|
+ super.eat(); // 先调用爷爷的 eat()
|
|
|
+ System.out.println("爸爸爱吃肉....");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Son.java —— 儿子类(继承 Dad)
|
|
|
+public class Son extends Dad {
|
|
|
+ public void eat() {
|
|
|
+ super.eat(); // 先调用爸爸的 eat()(爸爸内部又会调用爷爷的 eat())
|
|
|
+ System.out.println("儿子不吃饭....");
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**测试效果**:
|
|
|
+```java
|
|
|
+// Test02.java
|
|
|
+public class Test02 {
|
|
|
+ public static void main(String[] args) {
|
|
|
+ Son s = new Son();
|
|
|
+ s.eat();
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**预期输出**:
|
|
|
+```
|
|
|
+爷爷爱喝酒....
|
|
|
+爸爸爱吃肉....
|
|
|
+儿子不吃饭....
|
|
|
+```
|
|
|
+
|
|
|
+> **调用链分析**:`Son.eat()` → `super.eat()` 调用 `Dad.eat()` → `Dad.eat()` 中的 `super.eat()` 调用 `Granddad.eat()` → 输出"爷爷爱喝酒...." → 回到 Dad 输出"爸爸爱吃肉...." → 回到 Son 输出"儿子不吃饭...."。形成了方法的 **链式调用**。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 10. 同名属性的处理
|
|
|
+
|
|
|
+**文件**:`Bird.java`、`Penguin.java`、`Test01.java`
|
|
|
+
|
|
|
+当子类和父类定义了 **同名的成员变量** 时,两个变量会 **同时存在** 于子类对象中。访问规则如下:
|
|
|
+
|
|
|
+| 访问方式 | 访问的是 |
|
|
|
+|---------|---------|
|
|
|
+| `变量名` 或 `this.变量名` | **子类自己** 的属性 |
|
|
|
+| `super.变量名` | **父类** 的属性 |
|
|
|
+
|
|
|
+**示例**:
|
|
|
+```java
|
|
|
+// Bird.java —— 父类中定义了 s2(默认权限)、s3(protected 权限)
|
|
|
+public class Bird extends Animal {
|
|
|
+ String s2; // 默认权限
|
|
|
+ protected String s3; // protected 权限
|
|
|
+}
|
|
|
+
|
|
|
+// Penguin.java —— 子类中定义了同名的 s2、s3
|
|
|
+public class Penguin extends Bird {
|
|
|
+ String s3; // 与父类 Bird 的 s3 同名
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void fly() {
|
|
|
+ System.out.println("调用父类的s2属性:" + super.s2); // 访问 Bird 的 s2
|
|
|
+ System.out.println("调用自己的s2属性:" + this.s2); // 访问 Penguin 的 s2(如果没有则继承 Bird 的)
|
|
|
+ System.out.println("调用父类的s3属性:" + super.s3); // 访问 Bird 的 s3
|
|
|
+ System.out.println("调用自己的s3属性:" + this.s3); // 访问 Penguin 的 s3
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**测试效果**:
|
|
|
+```java
|
|
|
+// Test01.java
|
|
|
+Penguin p = new Penguin();
|
|
|
+p.s3 = "哈哈哈哈"; // 设置 Penguin 自己的 s3
|
|
|
+p.s2 = "s2222222"; // 设置 Bird 的 s2(Penguin 没有同名 s2,所以直接继承使用)
|
|
|
+p.fly();
|
|
|
+```
|
|
|
+
|
|
|
+> **总结**:如果子类没有定义同名的属性,`this.属性` 和 `super.属性` 访问的是同一个父类属性。如果子类定义了同名属性,则 `this` 访问自己的,`super` 访问父类的。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 11. Java 继承的限制
|
|
|
+
|
|
|
+**文件**:`Demo01.java`
|
|
|
+
|
|
|
+Java 的继承机制有以下重要限制:
|
|
|
+
|
|
|
+#### ① 单继承(Single Inheritance)
|
|
|
+Java 中一个子类 **只能有一个直接父类**,不支持 C++ 中的多继承。
|
|
|
+
|
|
|
+```java
|
|
|
+// ❌ 错误:Java 不支持多继承
|
|
|
+class C extends A, B { // 编译报错!
|
|
|
+}
|
|
|
+
|
|
|
+// ✅ 正确:一个子类只能有一个直接父类
|
|
|
+class B extends A { // 正确
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+#### ② 多层继承(Multi-level Inheritance)
|
|
|
+Java **支持多层继承**,即一个类的父类可以继承自其他类。
|
|
|
+
|
|
|
+```java
|
|
|
+// ✅ 多层继承:Son → Dad → Granddad
|
|
|
+class Granddad { }
|
|
|
+class Dad extends Granddad { } // Dad 的直接父类是 Granddad
|
|
|
+class Son extends Dad { } // Son 的直接父类是 Dad
|
|
|
+ // Son 的间接父类是 Granddad
|
|
|
+```
|
|
|
+
|
|
|
+| 概念 | 说明 |
|
|
|
+|------|------|
|
|
|
+| **直接父类** | 子类通过 `extends` 直接继承的类(如 Son 的 Dad) |
|
|
|
+| **间接父类** | 子类的父类的父类……(如 Son 的 Granddad) |
|
|
|
+
|
|
|
+#### ③ Object——所有类的根父类
|
|
|
+
|
|
|
+**文件**:`Demo01.java`
|
|
|
+
|
|
|
+Java 中 **所有的类都默认继承自 `Object` 类**。如果一个类没有显式使用 `extends` 关键字,它也会隐式继承 `Object`。
|
|
|
+
|
|
|
+```java
|
|
|
+// 以下两种写法等价:
|
|
|
+public class Animal { } // 隐式继承 Object
|
|
|
+public class Animal extends Object { } // 显式继承 Object
|
|
|
+```
|
|
|
+
|
|
|
+`Object` 类中定义了一些所有对象都具备的基本方法(如 `toString()`、`equals()`、`hashCode()` 等)。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 12. 访问修饰符在继承中的体现
|
|
|
+
|
|
|
+**文件**:`Bird.java`
|
|
|
+
|
|
|
+子类能访问的父类成员范围取决于父类成员的访问修饰符:
|
|
|
+
|
|
|
+| 修饰符 | 本类 | 同包子类 | 异包子类 | 所有类 |
|
|
|
+|--------|:----:|:--------:|:--------:|:------:|
|
|
|
+| `private` | ✅ | ❌ | ❌ | ❌ |
|
|
|
+| 默认(缺省) | ✅ | ✅ | ❌ | ❌ |
|
|
|
+| `protected` | ✅ | ✅ | ✅ | ❌ |
|
|
|
+| `public` | ✅ | ✅ | ✅ | ✅ |
|
|
|
+
|
|
|
+```java
|
|
|
+public class Bird extends Animal {
|
|
|
+ private String s1; // 私有的 —— 仅本类可访问
|
|
|
+ String s2; // 默认的 —— 同包可访问
|
|
|
+ protected String s3; // protected —— 同包 + 子类可访问
|
|
|
+ public String s4; // 公共的 —— 所有类可访问
|
|
|
+}
|
|
|
+```
|
|
|
|
|
|
**包名**:`exercise.studentSystem`
|
|
|
|
|
|
@@ -446,22 +682,33 @@ public class BookManagerTest {
|
|
|
|--------|---------|------|
|
|
|
| **继承的概念** | ⭐⭐⭐⭐⭐ | Java 三大特征之一,子类 extends 父类 |
|
|
|
| **继承的格式** | ⭐⭐⭐⭐⭐ | `class 子类 extends 父类 {}` |
|
|
|
-| **继承的好处** | ⭐⭐⭐⭐ | 提高代码复用性和可维护性 |
|
|
|
-| **继承的弊端(耦合性)** | ⭐⭐⭐⭐ | 父类变化影响子类,降低独立性 |
|
|
|
+| **继承的好处与弊端** | ⭐⭐⭐⭐ | 提高复用性但增强耦合性 |
|
|
|
| **is...a 关系判断** | ⭐⭐⭐⭐ | 使用继承前必须判断是否符合 is...a |
|
|
|
-| **多层继承** | ⭐⭐⭐ | 一个类可继承自另一个已继承的子类 |
|
|
|
+| **方法重写(Override)** | ⭐⭐⭐⭐⭐ | 子类覆盖父类方法,方法签名必须完全一致 |
|
|
|
+| **@Override 注解** | ⭐⭐⭐⭐ | 可选的检查注解,推荐加上帮助编译器校验 |
|
|
|
+| **super 关键字** | ⭐⭐⭐⭐⭐ | `super.方法()` 调用父类方法,`super.属性` 访问父类属性 |
|
|
|
+| **同名属性处理** | ⭐⭐⭐⭐ | 父子类同名属性同时存在,`this` 访问自己的,`super` 访问父类的 |
|
|
|
+| **单继承** | ⭐⭐⭐⭐⭐ | Java 一个子类只能有一个直接父类 |
|
|
|
+| **多层继承** | ⭐⭐⭐⭐ | 支持链式继承(Son → Dad → Granddad) |
|
|
|
+| **Object 根类** | ⭐⭐⭐⭐ | Java 所有类都隐式继承 Object |
|
|
|
+| **访问修饰符在继承中** | ⭐⭐⭐⭐ | `private` 不可继承,`protected` 子类可访问 |
|
|
|
| **构造方法 + 对象数组 + 冒泡排序综合应用** | ⭐⭐⭐⭐⭐ | 学生管理系统、图书管理系统 |
|
|
|
|
|
|
### 注意事项
|
|
|
|
|
|
-1. **继承是单继承**:Java 中一个类只能有一个直接父类(单继承体系)
|
|
|
-2. **私有成员不可继承**:子类不能使用父类中 `private` 修饰的成员
|
|
|
-3. **构造方法不可继承**:父类的构造方法不会被子类继承,但子类可以通过 `super()` 调用
|
|
|
-4. **继承的耦合性**:合理设计继承层次,避免过深的继承链
|
|
|
+1. **单继承**:Java 中一个类只能有一个直接父类(区别于 C++ 的多继承)
|
|
|
+2. **多层继承 ≠ 多继承**:Java 支持 Son → Dad → Granddad 这样的链式继承,但不支持同时继承多个类
|
|
|
+3. **私有成员不可访问**:子类不能直接使用父类 `private` 修饰的成员
|
|
|
+4. **构造方法不可继承**:父类的构造方法不会被子类继承,子类通过 `super(参数)` 调用父类构造方法
|
|
|
+5. **方法重写 vs 方法重载**:
|
|
|
+ - 重写(Override):父子类之间,方法签名完全一致
|
|
|
+ - 重载(Overload):同一个类中,方法名相同参数列表不同
|
|
|
+6. **`@Override` 注解**:不强制但建议加上,可以帮助编译器检查是否真正重写了父类方法
|
|
|
+7. **继承的耦合性**:合理设计继承层次,避免过深的继承链,优先考虑组合而非继承
|
|
|
|
|
|
### 拓展阅读
|
|
|
|
|
|
-- Java 继承中 `super` 关键字的使用
|
|
|
-- 方法重写(Override)与方法重载(Overload)的区别
|
|
|
- `final` 关键字对继承的限制(`final` 类不能被继承,`final` 方法不能被重写)
|
|
|
- 继承与组合(Composition)的对比——优先使用组合而非继承
|
|
|
+- `Object` 类的常见方法:`toString()`、`equals()`、`hashCode()`、`getClass()`
|
|
|
+- 方法重写的规则(访问权限不能更低、返回值类型可以协变、抛出异常不能更宽等)
|