让全家人像养育宝可梦一样学习面向对象编程的超强Java入门书～将热情转化为学习的神奇绘本～


# 📚 宝可梦与Java编程：目录（简体中文版）

- 🔹 [第1章 创建宝可梦图鉴！类的设计图](#第1章-创建宝可梦图鉴类的设计图)
- 🔹 [1.1 什么是对象](#11-什么是对象)
- 🔹 [1.2 创建类](#12-创建类)
- 🔹 [1.3 总结与测试](#13-总结与测试)
- 🔹 [第2章 从精灵球中召唤！实例的创建与使用](#第2章-从精灵球中召唤实例的创建与使用)
- 🔹 [2.1 创建实例](#21-创建实例)
- 🔹 [2.2 Getter 和 Setter 的使用](#22-getter-和-setter-的使用)
- 🔹 [2.3 添加方法](#23-添加方法)
- 🔹 [2.4 总结与测试](#24-总结与测试)
- 🔹 [第3章 保护宝可梦的秘密！类的机制](#第3章-保护宝可梦的秘密类的机制)
- 🔹 [3.1 限制其他类的访问](#31-限制其他类的访问)
- 🔹 [3.2 成员机制](#32-成员机制)
- 🔹 [3.3 构造函数机制](#33-构造函数机制)
- 🔹 [3.4 总结与测试](#34-总结与测试)
- 🔹 [第4章 指向宝可梦！实例与引用的秘密](#第4章-指向宝可梦实例与引用的秘密)
- 🔹 [4.1 什么是引用](#41-什么是引用)
- 🔹 [4.2 注意引用](#42-注意引用)
- 🔹 [4.3 创建不可变类](#43-创建不可变类)
- 🔹 [4.4 引用类型](#44-引用类型)
- 🔹 [4.5 总结与测试](#45-总结与测试)
- 🔹 [第5章 设计原创宝可梦！对象建模](#第5章-设计原创宝可梦对象建模)
- 🔹 [5.1 实现功能的类](#51-实现功能的类)
- 🔹 [5.2 使用record](#52-使用record)
- 🔹 [5.3 总结与测试](#53-总结与测试)
- 🔹 [第6章 揭开进化的秘密！继承的血统](#第6章-揭开进化的秘密继承的血统)
- 🔹 [6.1 类图](#61-类图)
- 🔹 [6.2 继承](#62-继承)
- 🔹 [6.3 继承规则](#63-继承规则)
- 🔹 [6.4 总结与测试](#64-总结与测试)
- 🔹 [第7章 宝可梦家族之谜！精通继承关系](#第7章-宝可梦家族之谜精通继承关系)
- 🔹 [7.1 继承树](#71-继承树)
- 🔹 [7.2 构造函数的链式调用](#72-构造函数的链式调用)
- 🔹 [7.3 多个类写在一个文件](#73-多个类写在一个文件)
- 🔹 [7.4 protected 修饰符](#74-protected-修饰符)
- 🔹 [7.5 总结与测试](#75-总结与测试)
- 🔹 [第8章 宝可梦的变身术！引用的自动类型转换](#第8章-宝可梦的变身术引用的自动类型转换)
- 🔹 [8.1 自动类型转换](#81-自动类型转换)
- 🔹 [8.2 向上与向下转型](#82-向上与向下转型)
- 🔹 [8.3 instanceof 运算符](#83-instanceof-运算符)
- 🔹 [8.4 使用 switch 判断类型](#84-使用-switch-判断类型)
- 🔹 [8.5 总结与测试](#85-总结与测试)
- 🔹 [第9章 一招多用！多态性（Polymorphism）](#第9章-一招多用多态性polymorphism)
- 🔹 [9.1 方法重载](#91-方法重载)
- 🔹 [9.2 方法重写](#92-方法重写)
- 🔹 [9.3 多态性](#93-多态性)
- 🔹 [9.4 总结与测试](#94-总结与测试)
- 🔹 [第10章 幻之宝可梦的谜团！抽象类的世界](#第10章-幻之宝可梦的谜团抽象类的世界)
- 🔹 [10.1 什么是抽象类](#101-什么是抽象类)
- 🔹 [10.2 继承抽象类](#102-继承抽象类)
- 🔹 [10.3 抽象类类图](#103-抽象类类图)
- 🔹 [10.4 总结与测试](#104-总结与测试)
- 🔹 [第11章 宝可梦的属性与能力！接口的力量](#第11章-宝可梦的属性与能力接口的力量)
- 🔹 [11.1 什么是接口](#111-什么是接口)
- 🔹 [11.2 转换为接口类型](#112-转换为接口类型)
- 🔹 [11.3 接口实现多态性](#113-接口实现多态性)
- 🔹 [11.4 接口继承接口](#114-接口继承接口)
- 🔹 [11.5 总结与测试](#115-总结与测试)
---

# 🧩 第1章 创建宝可梦图鉴！类的设计图

## 🎯 1.1 什么是对象

### 🌟 宝可梦也是对象？其实面向对象编程就在我们身边

在宝可梦的世界里，比如皮卡丘和小火龙，这些宝可梦就是“对象”。  
在现实生活中，自行车或智能手机也可以被视为对象。

对象有两个重要组成部分：

- 🧬 **属性（字段）**：比如皮卡丘的“类型”、“等级”等
- 🛠 **行为（方法）**：比如皮卡丘使用的“十万伏特”或“叫声”等技能

### 🧠 收集皮卡丘的状态！对象的魔力在于汇总数据

在 Java 中，对象就是将“数据（属性）”和“操作（方法）”整合在一起的结构。  
比如皮卡丘可以表示如下：

```java
// 皮卡丘这个对象的示例（伪代码）
名称: "皮卡丘"
类型: "电"
等级: 15
技能: 十万伏特, 叫声
```

## 🏗 1.2 创建类

### 📘 在图鉴中注册前！理解类作为设计图的重要性

类是“对象的设计图”。  
比如有一个“宝可梦”类，就可以根据它创建皮卡丘、小火龙等各种宝可梦对象。

---

### 🧠 使用类的好处是什么？

通过使用“类”来定义宝可梦，有哪些好处呢？请参看下表：

| 项目         | 仅用数组或变量时               | 使用类的好处                          |
|--------------|--------------------------------|--------------------------------------|
| 信息整合     | 分别管理 name、type、level     | 使用一个对象统一管理                 |
| 可扩展性     | 添加新属性时维护复杂             | 只需在类中添加字段或方法              |
| 可重用性     | 需要重复写相同的处理             | 可将共通处理封装成方法进行复用         |
| 可读性       | 信息之间的关联性不易看出         | 数据和行为统一表示，直观易懂           |
| 可维护性     | 难以发现 bug                    | 逻辑集中在类中，便于修改               |

---

### 🛠 类的定义示例（Java）

```java
// 宝可梦类的定义
public class Pokemon {
    String name; // 宝可梦名称（例：皮卡丘）
    String type; // 类型（例：电）
    int level;   // 等级（以整数表示）

    // 宝可梦的自我介绍方法
    public void introduce() {
        System.out.println("你好！我是" + name + "，类型是" + type + "，等级是" + level + "！");
    }
}
```

📝 本类中：
- `name`：以字符串形式管理宝可梦的名字。
- `type`：以字符串形式管理宝可梦的类型（如“火”、“草”）。
- `level`：以整数型管理等级。
- `introduce()`：输出宝可梦自我介绍的方法。

---

## 🧪 1.3 总结与测试

### ✅ 宝可梦类总结

| 要素   | 内容                     |
|--------|--------------------------|
| 类     | 设计图（宝可梦的共通信息） |
| 对象   | 实际创建出的皮卡丘、小火龙 |
| 属性   | 名称、类型、等级           |
| 方法   | 自我介绍等行为              |

---

### 📝 练习题

1. 设想一个属于你自己的宝可梦，用 `Pokemon` 类来表示。
2. 扩展 `introduce()` 方法，使其也能介绍宝可梦会使用的技能。

---

### 🔍 参考答案（含注释）

```java
public class Pokemon {
    String name;   // 名称
    String type;   // 类型
    int level;     // 等级
    String move;   // 技能

    public void introduce() {
        System.out.println("你好！我是" + name + "，类型是" + type + "，等级是" + level + "！");
        System.out.println("我会使用技能：「" + move + "」！");
    }
}

public class Main {
    public static void main(String[] args) {
        Pokemon pika = new Pokemon();  // 创建新的 Pokemon 实例
        pika.name = "皮卡丘";             // 设置名称
        pika.type = "电";                // 设置类型
        pika.level = 15;               // 设置等级
        pika.move = "十万伏特";          // 设置技能

        pika.introduce();             // 调用介绍方法
    }
}
```

🧩 通过使用类，我们可以方便地将一个宝可梦的信息和行为集中管理，非常实用。

🧩 本程序使用 `Pokemon` 类登记了皮卡丘的信息，并进行自我介绍。

---

# 🎯 第2章 从精灵球中召唤！实例的创建与使用

## 🧱 2.1 创建实例

### 🥚 召唤宝可梦！new 运算符和构造函数的魔法

在 Java 中，可以使用 `new` 关键字来从类中创建对象（实例）。  
这就像从精灵球中召唤出宝可梦一样。  
我们称将宝可梦从精灵球中释放出来的这个过程为 “实例化”。

也就是说，使用 `new` 抛出精灵球，就可以召唤出皮卡丘（实例）！

```java
Pokemon pika = new Pokemon();
```

- `Pokemon`：类的名称（设计图）
- `pika`：被创建的皮卡丘实例（对象）
- `new Pokemon()`：创建宝可梦的魔法指令（调用构造函数）

📝 这段代码的意思是“定义一个 Pokemon 类型的变量 pika，并用 new 创建的对象赋值给它”。

---

## 🔓 2.2 Getter 和 Setter 的使用方法

### 🔍 “你的HP是多少？”使用 Getter 查看状态

Getter 是用于获取对象中属性值的方法。

```java
public String getName() {
    return name;
}
```

---

### 💪 “升级啦！”使用 Setter 提升宝可梦实力

Setter 是用于修改对象属性的方法。

```java
public void setLevel(int lvl) {
    level = lvl;
}
```

---

## 🔍 为什么要使用 Getter 和 Setter？

在 Java 的面向对象编程中，使用 Getter 和 Setter 是为了实现 **封装（encapsulation）**。  
封装的目的是安全地管理类中的数据（字段），防止被外部随意篡改。

---

## 🧬 什么是封装？

封装是指：

> “不允许外部直接更改类内部的数据，必须通过安全的方法来操作”。

比如考虑宝可梦的 HP（体力）——如果可以随便被改为负数，那游戏平衡就被破坏了。

---

## 🧪 ❌ 不使用 Getter / Setter 的错误示例

```java
public class Pokemon {
    public int hp;  // 因为是 public，其他类可以自由访问
}

public class Main {
    public static void main(String[] args) {
        Pokemon pikachu = new Pokemon();
        pikachu.hp = -100; // 虽然不合理但可以直接赋值
    }
}
```

### 问题：

🚨 因为 `hp` 是 public，任何地方都可以直接修改它，  
比如设置成 -100 这样的值，明显违背了游戏规则。

---

## ✅ 使用 Getter / Setter 的正确示例

```java
public class Pokemon {
    private int hp;

    public void setHp(int hp) {
        if (hp >= 0) {
            this.hp = hp;
        } else {
            System.out.println("HP 必须大于等于 0。");
        }
    }

    public int getHp() {
        return this.hp;
    }
}
```

```java
public class Main {
    public static void main(String[] args) {
        Pokemon pikachu = new Pokemon();
        pikachu.setHp(100);
        System.out.println(pikachu.getHp());

        pikachu.setHp(-50);
        System.out.println(pikachu.getHp());
    }
}
```

### 🔍 解释：if (hp >= 0)

| 行号                          | 内容     | 说明                              |
|-------------------------------|----------|-----------------------------------|
| `if (hp >= 0)`               | 条件判断 | hp 大于等于 0 为真，否则为假       |
| `{ this.hp = hp; }`          | 成立时   | 正常值，赋值给字段 hp             |
| `else {`                     | 否则     | 执行错误处理逻辑                  |
| `System.out.println(...);`   | 错误输出 | 告知用户输入了无效值              |

---

### ✅ 输出示例：

```
100
HP 必须大于等于 0。
100
```

---

### 🎮 执行流程和输出结果

```
🔢 步骤1：设置正确值
-----------------------------
🧠 执行代码：
    pikachu.setHp(100);

✅ 判定：100 ≥ 0 → OK  
💾 设置结果：this.hp = 100

🖨 输出：
    System.out.println(pikachu.getHp());
📢 控制台显示：
    👉 100
```

```
🔢 步骤2：尝试设置错误值
-----------------------------
🧠 执行代码：
    pikachu.setHp(-50);

❌ 判定：-50 < 0 → NG  
🚫 设置结果：hp 未被更改

🖨 输出：
    System.out.println("HP 必须大于等于 0。");
📢 控制台显示：
    ⚠️ HP 必须大于等于 0。
```

```
🔢 步骤3：再次确认 HP
-----------------------------
🧠 执行代码：
    System.out.println(pikachu.getHp());

🗂 当前 hp：仍为 100（未被更改）

📢 控制台显示：
    👉 100
```

---

### 🧾 最终输出总结

```
100
HP 必须大于等于 0。
100
```

---

## 🎯 Getter / Setter 的优点总结

使用 Getter 和 Setter，可以 **安全、准确地管理宝可梦的能力值**。  
这就像在游戏中设置一个防作弊系统，防止随意设置超高 HP。

| 🧩 项目         | ✅ 优点                       | 🔍 宝可梦示例                          |
|----------------|------------------------------|----------------------------------------|
| **提高安全性**   | 阻止非法值输入                 | 防止 HP 被设为负数或 9999              |
| **增强灵活性**   | 便于未来扩展                 | 例如“等级 ≥50 才能进化”的判断          |
| **提升可读性**   | 使用方式更明确               | 可以只提供 getter 实现只读效果         |
| **加强封装性**   | 隐藏内部实现                 | 对外隐藏内部逻辑，比如计算或验证规则   |

---

### ✨ 搭配 Getter / Setter 的 Pokemon 类示例

```java
public class Pokemon {

    private String name;
    private String type;
    private int level;
    private String move;

    public void setName(String name) { this.name = name; }
    public void setType(String type) { this.type = type; }
    public void setLevel(int level) { this.level = level; }
    public void setMove(String move) { this.move = move; }

    public String getName() { return name; }
    public String getType() { return type; }
    public int getLevel() { return level; }
    public String getMove() { return move; }
}
```

---

## 🛠 2.3 添加方法

### ⚡ 实现“十万伏特”！添加技能使用方法

```java
public void useMove() {
    System.out.println(name + "使用了" + move + "！效果拔群！");
}
```

📝 此方法在宝可梦使用技能时输出战斗台词。

---

## ✅ 进阶：使用 `@Override` 与 `toString`

### 📢 应用篇：“皮卡丘，介绍一下你自己！”使用 toString 方法

```java
@Override
public String toString() {
    return "宝可梦：" + name + " / 类型：" + type + " / 等级：" + level + " / 技能：" + move;
}
```

🧩 `@Override` 并非必需，但推荐使用，它可以告诉编译器你在重写父类方法，避免出错。

---

## 🎯 2.4 总结与测试

### ✅ 实例操作重点

#### 🎮 基础

| 术语       | 说明                      |
|------------|---------------------------|
| 实例       | 使用 new 创建的对象        |
| Getter     | 获取字段值的方法           |
| Setter     | 设置字段值的方法           |

#### 📢 进阶

| 术语         | 说明                                   |
|--------------|----------------------------------------|
| `@Override`  | 指明正在重写父类方法（如 Object.toString） |
| `toString`   | 将对象转换为字符串                     |
| 自定义方法    | 可以添加如技能使用等原创方法             |

---

### 🧪 最终测试示例

```java
public class Pokemon {
    private String name;
    private String type;
    private int level;
    private String move;

    public void setName(String name) { this.name = name; }
    public void setType(String type) { this.type = type; }
    public void setLevel(int level) { this.level = level; }
    public void setMove(String move) { this.move = move; }

    public String getName() { return name; }
    public String getType() { return type; }
    public int getLevel() { return level; }
    public String getMove() { return move; }

    public void useMove() {
        System.out.println(name + "使用了" + move + "！效果拔群！");
    }

    @Override
    public String toString() {
        return "宝可梦：" + name + " / 类型：" + type + " / 等级：" + level + " / 技能：" + move;
    }
}

public class Main {
    public static void main(String[] args) {
        Pokemon pika = new Pokemon();
        pika.setName("皮卡丘");
        pika.setType("电");
        pika.setLevel(25);
        pika.setMove("十万伏特");

        System.out.println(pika);  // 自动调用 toString 方法
        pika.useMove();            // 使用技能
    }
}
```

🧩 本示例展示了从类 → 创建实例 → 设置值 → 执行方法的完整流程！

---


# 🛡 第3章 保护宝可梦的秘密！类的机制

## 🔐 3.1 限制其他类的访问

### 🧳 “HP不能随便被看到！”private 与 public 的界限

像宝可梦的“HP”或“已学习技能”等信息，如果被其他训练师随意查看或修改，会造成问题。  
在 Java 中，可以使用“访问修饰符”来保护类中的信息。

```java
public class Pokemon {
    private int hp; // 设置为 private，使其他类无法直接访问

    public int getHp() {
        return hp; // 提供安全访问的方法
    }

    public void setHp(int hp) {
        this.hp = hp; // 提供外部设置的方法
    }
}
```

📝 `private` 表示私有，`public` 表示公开。

---

### 🧩 灰色地带的属性！没有修饰符的世界

如果不写任何修饰符（即“默认”访问权限），该字段只在“同一包”中可见。  
Java 中推荐明确指定访问权限，以确保代码安全性和可维护性。

---

### 🛡 守护秘密状态！封装的核心思想

**封装（Encapsulation）** 是将数据封闭在类内部，并通过公开的接口访问。  
就像宝可梦的状态界面只允许训练师操作，其他人无权干涉。

---

## ⚙️ 3.2 成员的机制

### ⚡ “所有宝可梦的共通特性”——静态成员的力量

某些特性，如“最大等级 100”，对所有宝可梦都适用。  
这类共通数据应使用 `static` 修饰。

```java
public class Pokemon {
    public static final int MAX_LEVEL = 100; // 所有宝可梦共通
}
```

📝 `static` 表示该成员属于类，而非实例。

---

### 🧬 “这个皮卡丘独有的特性”——实例成员的个性

每个宝可梦的“等级”、“名称”等信息都是实例独有的，应使用实例成员表示。

```java
public class Pokemon {
    private int level; // 每只宝可梦不同
}
```

---

### ⚠️ 静态和实例可以共存吗？

当然可以，但要注意它们的作用域不同。

```java
public class Pokemon {
    public static final int MAX_LEVEL = 100;
    private int level;

    public boolean isMaxLevel() {
        return level == MAX_LEVEL; // 与类变量比较
    }
}
```

---

## 🧱 3.3 构造函数的机制

### 🌀 同名但参数不同！构造函数的重载魔法

Java 允许一个类有多个构造函数（方法重载）。

```java
public Pokemon() {
    this.name = "皮卡丘"; // 默认构造
}

public Pokemon(String name) {
    this.name = name; // 使用参数初始化
}
```

---

### 🌈 “闪光宝可梦也能创建！”添加更多构造函数

```java
public Pokemon(String name, int level, String type) {
    this.name = name;
    this.level = level;
    this.type = type;
}
```

---

### 🔁 用 this 实现构造函数之间的配合

```java
public Pokemon(String name, int level) {
    this(name, level, "普通"); // 调用另一个构造函数
}
```

📝 `this(...)` 用于调用同一个类中的其他构造函数。

---

### 🧊 什么是默认构造函数？

如果一个类中没有定义任何构造函数，Java 会自动提供一个无参构造函数。  
但如果你写了任何构造函数（有参的），默认构造函数将不再自动生成。

---

## 🧪 3.4 总结与测试

### 📘 第3章总结：封装与成员管理的精髓

| 项目         | 内容                                        |
|--------------|---------------------------------------------|
| 访问修饰符    | 控制数据的访问权限（public / private）       |
| private      | 仅类内部可见                                 |
| public       | 对外公开                                    |
| static       | 所有实例共通                                 |
| 构造函数      | 创建对象时调用的方法                          |
| this         | 指代自身或调用自身的构造方法                   |

---

### 🎮 测试代码：第3章综合示例

```java
public class Pokemon {
    private String name;
    private String type;
    private int level;
    public static final int MAX_LEVEL = 100;

    public Pokemon() {
        this("皮卡丘", 5, "电");
    }

    public Pokemon(String name, int level, String type) {
        this.name = name;
        this.level = level;
        this.type = type;
    }

    public String getName() { return name; }
    public String getType() { return type; }
    public int getLevel() { return level; }

    public void setLevel(int level) { this.level = level; }

    public boolean isMaxLevel() {
        return level == MAX_LEVEL;
    }

    public void introduce() {
        System.out.println("我是" + name + "！类型：" + type + "，等级：" + level);
    }
}

public class Main {
    public static void main(String[] args) {
        Pokemon pika = new Pokemon(); // 默认构造函数
        pika.introduce();

        Pokemon eve = new Pokemon("伊布", 10, "普通");
        eve.introduce();

        System.out.println("伊布是否满级？：" + eve.isMaxLevel());
    }
}
```

🧩 本示例展示了 **封装、static 成员、构造函数重载** 等核心概念！

---

# 🧭 第4章 指向宝可梦！实例与引用的秘密

## 🎯 4.1 什么是引用

### 🎈 精灵球与宝可梦的关系？引用的神奇作用

在宝可梦的世界中，“精灵球”就像是储存宝可梦的容器。  
在 Java 中，精灵球就像是“引用（Reference）”。

```java
Pokemon pika1 = new Pokemon(); // 创建一个宝可梦对象
Pokemon pika2 = pika1;         // 将 pika1 的引用赋给 pika2
```

📝 `pika2` 只是“指向”与 `pika1` 相同的宝可梦，并不是新建了一个宝可梦。

---

## 👀 4.2 注意引用的副作用

### 🧪 “复制了？其实是同一个宝可梦！”变量赋值的真相

```java
pika2.setLevel(50); // 修改 pika2 的等级
System.out.println(pika1.getLevel()); // pika1 也被影响了！
```

📌 在 Java 中，变量存储的是“对象地址”，而不是对象本身。

---

### ✨️ 提示：如果想要“完全相同但独立”的个体，需要实现“复制机制”。

---

## 🧊 4.3 创建完全不可变的类

### 🧼 “谁都无法改变的传说宝可梦”不可变类的实现方式

```java
public final class Pokemon {
    private final String name;
    private final String type;
    private final int level;

    public Pokemon(String name, String type, int level) {
        this.name = name;
        this.type = type;
        this.level = level;
    }

    public String getName() { return name; }
    public String getType() { return type; }
    public int getLevel() { return level; }
}
```

🛡 所有字段都是 `final`，一旦创建就无法更改。

---

## 🧬 4.4 引用类型

### 🧪 “与基本类型有何不同？”Java 类型系统解剖

| 类型分类   | 示例                     | 特点                   |
|------------|--------------------------|------------------------|
| 基本类型   | `int`, `double`, `boolean` | 存储值本身             |
| 引用类型   | `String`, `Pokemon`, `List` | 存储对象的地址（引用） |

---

### ⚠️ “空的精灵球？”null 的真相与风险

```java
Pokemon pika = null; // 还未指向任何宝可梦
pika.introduce();    // ❌ 报错！（NullPointerException）
```

🚨 null 表示“没有指向任何对象”，调用方法会导致程序崩溃！

---

## 🧪 4.5 总结与测试

### 🧾 第4章总结：理解引用与不可变性

| 关键词     | 内容                                     |
|------------|------------------------------------------|
| 引用       | 指向对象内存地址的变量                     |
| 相同引用   | 赋值变量时，两个变量指向同一对象            |
| null      | 没有引用对象，调用方法将报错（NullPointerException） |
| 不可变类   | 所有属性设为 final，创建后不能再更改         |

---

### 🧪 综合测试代码

```java
public final class Pokemon {
    private final String name;
    private final String type;
    private final int level;

    public Pokemon(String name, String type, int level) {
        this.name = name;
        this.type = type;
        this.level = level;
    }

    public String getName() { return name; }
    public String getType() { return type; }
    public int getLevel() { return level; }

    public void introduce() {
        System.out.println("我是" + name + "！类型：" + type + "，等级：" + level);
    }
}

public class Main {
    public static void main(String[] args) {
        Pokemon pika1 = new Pokemon("皮卡丘", "电", 25);
        Pokemon pika2 = pika1; // 引用相同对象

        pika1.introduce();
        pika2.introduce();

        // Pokemon empty = null;
        // empty.introduce(); // ❌ NullPointerException
    }
}
```

🔍 本章通过代码体验了引用的本质、null 的风险以及不可变对象的实现方法。

---

# 🧪 第5章 设计原创宝可梦！对象建模

## 🧱 5.1 实现功能的类

### 📝 “想设计什么样的宝可梦？”构建处理逻辑的整体视角

在宝可梦游戏中，一个宝可梦包括名字、类型、等级、学习的技能等信息。  
我们要思考如何通过类来表示这些内容——这就是 **对象建模（Object Modeling）**。

---

### 🧮 “决定特性和技能”绘制类的设计图

```java
public class Pokemon {
    private String name;      // 宝可梦的名字（如：妙蛙种子）
    private String type;      // 宝可梦的类型（如：草）
    private int level;        // 等级（用整数表示）
    private String[] moves;   // 学习的技能（用数组管理）

    public Pokemon(String name, String type, int level, String[] moves) {
        this.name = name;
        this.type = type;
        this.level = level;
        this.moves = moves;
    }

    public void introduce() {
        System.out.println("名字：" + name + " / 类型：" + type + " / 等级：" + level);
        System.out.println("学习的技能：");
        for (String move : moves) {
            System.out.println("- " + move);
        }
    }
}
```

📝 此类包含基本属性和技能列表，并通过介绍方法输出信息。

---

### 🚀 “确定没问题吗？”检查最终规格点

- 技能数量：使用数组灵活处理
- 等级上限：可用 `static final` 固定
- 多重类型：此处为简化版，仅允许单一类型（可扩展）

---

### ⚙️ “开始实现！”从设计图生成代码的技巧

```java
String[] fushiMoves = {"撞击", "藤鞭", "毒粉"};
Pokemon fushigidane = new Pokemon("妙蛙种子", "草", 10, fushiMoves);
fushigidane.introduce();
```

📝 使用 `String[]` 打包多个技能传入构造函数。

---

## 📦 5.2 使用 record（Java 16+）

### 🆕 “Java 16 的新特性！”record 是什么？

Java 16 引入了 `record`，可用于简洁地定义数据类。

```java
public record SimplePokemon(String name, String type, int level) {}
```

---

### ✨️ “简易宝可梦图鉴条目”record 的定义与自动功能

record 自动生成：

- 构造函数
- getter
- toString()
- equals()

```java
SimplePokemon zenigame = new SimplePokemon("杰尼龟", "水", 8);
System.out.println(zenigame.name());  // 获取字段值
System.out.println(zenigame);         // 自动 toString
```

---

### 🧠 “想再加强？”为 record 添加方法

record 也可以包含方法。

```java
public record SimplePokemon(String name, String type, int level) {
    public boolean isStarter() {
        return level <= 10;
    }
}
```

---

### 🔒 “无法被改变的传说宝可梦”record 的不可变特性

record 所有字段默认是 `final`，对象不可更改。  
非常适合表示如梦幻、洛奇亚等传说宝可梦。

---

### 🪄 “三行代码生成宝可梦！”record 快速使用技巧

```java
SimplePokemon hitokage = new SimplePokemon("小火龙", "火", 5);
System.out.println("首发候选：" + hitokage.name());
```

---

## 🎯 5.3 总结与测试

### ✅ 对象建模与 record 的要点

| 概念       | 说明                         |
|------------|------------------------------|
| 对象建模   | 用代码表示现实世界中的宝可梦     |
| 字段       | 名称、类型、技能等信息           |
| 方法       | 自我介绍、技能使用等行为         |
| record     | 简化数据类写法（不可变、轻量）    |
| 不可变性   | 一经创建不能更改状态，确保安全性  |

---

### 💻 综合示例代码

```java
public class Pokemon {
    private String name;
    private String type;
    private int level;
    private String[] moves;

    public Pokemon(String name, String type, int level, String[] moves) {
        this.name = name;
        this.type = type;
        this.level = level;
        this.moves = moves;
    }

    public void introduce() {
        System.out.println("名字：" + name + " / 类型：" + type + " / 等级：" + level);
        System.out.println("学习的技能：");
        for (String move : moves) {
            System.out.println("- " + move);
        }
    }
}

public record SimplePokemon(String name, String type, int level) {
    public boolean isStarter() {
        return level <= 10;
    }
}

public class Main {
    public static void main(String[] args) {
        String[] moves = {"撞击", "藤鞭", "毒粉"};
        Pokemon bulbasaur = new Pokemon("妙蛙种子", "草", 10, moves);
        bulbasaur.introduce();

        SimplePokemon charmander = new SimplePokemon("小火龙", "火", 5);
        System.out.println("首发候选：" + charmander.name());
        System.out.println("是否为首发宝可梦？：" + charmander.isStarter());
    }
}
```

🧩 本章对比了类与 record 的用法，同时实践了数据建模与不可变设计！

---


# 🧬 第6章 揭开进化的秘密！继承的血统

## 📊 6.1 类图

### 📚 “宝可梦图鉴背后的结构”类图的解读方法

Java 的继承关系，就像宝可梦的进化树一样。  
比如“皮丘 → 皮卡丘 → 雷丘”可以用类图表示如下：

```
Pokemon（父类）
  └─ Pikachu（子类）
       └─ Raichu（孙类）
```

📝 共通信息写在父类中，新增能力写在子类中。

---

### ✨️ 提示：没有类图工具时，也可以用文字和缩进表达继承关系。

---

## 🧪 6.2 继承

### 👪 “从皮丘到皮卡丘”继承让类更强大

```java
public class Pokemon {
    String name;
    String type;

    public void introduce() {
        System.out.println("我是" + name + "，类型是" + type + "！");
    }
}

public class Pikachu extends Pokemon {
    int level;

    public void thunderbolt() {
        System.out.println(name + "使用了十万伏特！");
    }
}
```

📝 `Pikachu` 类继承了 `Pokemon` 类，增加了 `level` 字段和 `thunderbolt()` 方法。

---

### 🐣 “从蛋中孵化”实例初始化顺序

Java 中构造函数的调用顺序是：**先调用父类构造函数，再调用子类构造函数**

```java
public class Pokemon {
    public Pokemon() {
        System.out.println("宝可梦诞生了！");
    }
}

public class Pikachu extends Pokemon {
    public Pikachu() {
        System.out.println("皮卡丘诞生了！");
    }
}
```

输出顺序：

```
宝可梦诞生了！
皮卡丘诞生了！
```

---

### 🚀 “进化后的能力”继承的效果演示

```java
Pikachu pika = new Pikachu();
pika.name = "皮卡丘";
pika.type = "电";
pika.level = 15;

pika.introduce();     // 父类方法
pika.thunderbolt();   // 子类独有方法
```

---

## 📜 6.3 继承的规则

### 🧠 “X 是 Y 吗？”理解 is-a 关系

“皮卡丘是宝可梦” 这个关系成立，因此 `Pikachu` 可以继承 `Pokemon`。  
但“宝可梦是皮卡丘” 不成立，不能反向继承。

---

### 🚫 “传说宝可梦不能再进化”无法继承的类

```java
public final class Mewtwo extends Pokemon {
    // 不能被其他类继承
}
```

📝 使用 `final` 修饰类，表示该类无法被继承。

---

### 🔒 “限定继承者”sealed class 的威力（Java 17+）

```java
public sealed class Pokemon permits Pikachu, Eevee {}
```

表示只有 `Pikachu` 和 `Eevee` 可以继承 `Pokemon`。

---

### 🧙 “独门技能”不可继承的成员

- `private` 方法或字段不能被子类访问
- `final` 方法不能被重写（override）

---

## 🎯 6.4 总结与测试

### 📘 第6章总结

| 概念        | 说明                           |
|-------------|--------------------------------|
| 继承（extends） | 继承父类功能                    |
| 父类        | 定义共通属性和方法的类            |
| 子类        | 添加特有功能的类                  |
| is-a 关系   | 判断是否适合用继承表达的条件        |
| final       | 禁止被继承                        |
| sealed（Java17） | 限定哪些类可以继承该类            |

---

### 💻 综合示例代码

```java
public class Pokemon {
    String name;
    String type;

    public void introduce() {
        System.out.println("我是" + name + "，类型是" + type + "！");
    }
}

public class Pikachu extends Pokemon {
    int level;

    public Pikachu(String name, int level) {
        this.name = name;
        this.type = "电";
        this.level = level;
    }

    public void thunderbolt() {
        System.out.println(name + "使用了十万伏特！ 效果拔群！");
    }
}

public class Main {
    public static void main(String[] args) {
        Pikachu pika = new Pikachu("皮卡丘", 20);
        pika.introduce();       // 调用父类方法
        pika.thunderbolt();     // 调用子类方法
    }
}
```

🧩 本章实践了继承、构造函数调用顺序、方法扩展等重要概念！

---

# 🌳 第7章 宝可梦家族之谜！精通继承关系

## 🌳 7.1 继承树

### 🧭 “宝可梦进化的族谱图”完整继承树展示

宝可梦具有类似家族树的进化路径。  
Java 中也可以通过继承结构来表现。

示例：喵喵 → 喵头目（地区进化）

```
Pokemon
├── Meowth
│   └── Perrserker
└── Eevee
    ├── Vaporeon
    ├── Jolteon
    └── Flareon
```

---

### 🧬 “所有宝可梦的祖先”Object 类的秘密

Java 中所有类默认都继承自 `Object` 类。

```java
public class Pikachu {
    // 自动继承 Object 中的 toString()、equals() 等方法
}
```

📝 所以每个类都具备一些基本功能，比如打印字符串表示、比较等。

---

## 🔗 7.2 构造函数的链式调用

### 👶 “父传子的初始化”构造函数的调用顺序

Java 要求子类必须先调用父类构造函数。

```java
public class Pokemon {
    public Pokemon(String name) {
        System.out.println(name + " 诞生了！");
    }
}

public class Eevee extends Pokemon {
    public Eevee() {
        super("伊布"); // 调用父类构造函数
        System.out.println("伊布准备完毕！");
    }
}
```

输出：

```
伊布 诞生了！
伊布准备完毕！
```

---

### ❓ “省略 super() 会怎样？”

如果父类有无参构造函数，可以省略 super()，会自动调用。  
但如果父类只有带参构造函数，必须显式调用 super(...)

---

## 📁 7.3 多个类写在同一个文件中

### 📄 “进化前后一起定义！”技巧：一个文件多类

```java
public class Pokemon {
    String name;
    public void greet() {
        System.out.println("你好，我是 " + name + "！");
    }
}

class Pikachu extends Pokemon {
    public Pikachu() {
        name = "皮卡丘";
    }
}
```

📝 若文件名为 `Pokemon.java`，则只能将 `Pokemon` 类设为 public，其他类省略 public。

---

## 🛡 7.4 protected 修饰符

### 🏠 “只对家族开放”protected 的特殊权限

```java
public class Pokemon {
    protected String name; // 可在子类或同包类中访问
}
```

---

### ⚠️ “滥用会带来风险！”使用 protected 时的注意事项

- 不代表“只能在继承链使用”，同包下其他类也能访问
- 跨包访问需通过继承关系实现

---

### 🌐 “public、private、protected、默认”四种权限的对比

| 修饰符      | 同类内 | 同包内 | 子类（跨包） | 外部类 |
|-------------|--------|--------|---------------|--------|
| public      | ✅     | ✅     | ✅            | ✅     |
| protected   | ✅     | ✅     | ✅            | ❌     |
| 默认（无修饰） | ✅     | ✅     | ❌            | ❌     |
| private     | ✅     | ❌     | ❌            | ❌     |

---

## 🎯 7.5 总结与测试

### 🧾 第7章总结：掌握 Java 的继承结构

| 概念        | 内容                                         |
|-------------|----------------------------------------------|
| 继承树      | 类之间的层级关系                                |
| Object 类   | 所有类的终极父类                                |
| super()     | 显式调用父类构造函数                            |
| protected   | 子类与同包可访问                                |

---

### 💻 综合示例代码

```java
public class Pokemon {
    protected String name;

    public Pokemon(String name) {
        this.name = name;
        System.out.println(name + " 诞生了！");
    }

    public void greet() {
        System.out.println("你好！我是 " + name + "！");
    }
}

class Pikachu extends Pokemon {
    public Pikachu() {
        super("皮卡丘");
        System.out.println("皮卡丘准备好了！");
    }

    public void thunderbolt() {
        System.out.println(name + " 使用了十万伏特！");
    }
}

public class Main {
    public static void main(String[] args) {
        Pikachu pika = new Pikachu();
        pika.greet();           // 父类方法
        pika.thunderbolt();     // 子类方法
    }
}
```

🎉 本章掌握了继承结构、protected、类共存与构造顺序等高级技巧！

---

# 🌀 第8章 宝可梦的变身术！引用的自动类型转换

## 🪄 8.1 引用的自动类型转换

### 🔁 “百变怪的变身”自动类型转换的概念

Java 中，子类对象可以赋值给父类类型的变量。  
这就像百变怪变身为其他宝可梦，用他们的方式战斗！

```java
Pokemon pika = new Pikachu("皮卡丘", 20);
pika.introduce(); // 调用的是父类方法
```

📝 子类 `Pikachu` 的对象被赋值给 `Pokemon` 类型的变量。

---

## 🧱 8.2 向上转型与向下转型

### ⬆️ 向上转型（Upcasting）

从子类转换为父类类型，自动完成。

```java
Pokemon poke = new Pikachu("皮卡丘", 20);
```

---

### ⬇️ 向下转型（Downcasting）

从父类转换为子类类型，需要显式转换。

```java
Pikachu pika = (Pikachu) poke; // 强制类型转换
pika.thunderbolt(); // 子类特有方法
```

⚠️ 若 poke 实际不是 Pikachu 类型，会抛出 `ClassCastException`！

---

## 🔍 8.3 instanceof 运算符

### 🧪 “你真的是皮卡丘吗？”使用 instanceof 判断类型

```java
if (poke instanceof Pikachu) {
    Pikachu pika = (Pikachu) poke;
    pika.thunderbolt();
}
```

📝 `instanceof` 用于判断一个对象是否属于某种类型。

---

## 🧠 8.4 使用 switch 判断类型（Java 14+）

### 🌀 “根据类型释放不同技能”使用类型匹配的 switch 表达式

```java
switch (poke) {
    case Pikachu p -> p.thunderbolt();
    case Eevee e -> e.adapt();
    default -> System.out.println("未知的宝可梦！");
}
```

📝 Java 14 开始支持带模式匹配的 switch 表达式，简洁易用。

---

## 🎯 8.5 总结与测试

### 📘 第8章总结：掌握类型转换和多态基础

| 概念          | 说明                             |
|---------------|----------------------------------|
| 向上转型      | 子类 → 父类，自动完成              |
| 向下转型      | 父类 → 子类，需强制转换             |
| instanceof    | 判断对象类型的关键字                |
| switch 表达式 | Java 14+ 中的类型匹配语法           |

---

### 💻 综合示例代码

```java
public class Pokemon {
    protected String name;

    public Pokemon(String name) {
        this.name = name;
    }

    public void introduce() {
        System.out.println("我是 " + name + "！");
    }
}

class Pikachu extends Pokemon {
    private int level;

    public Pikachu(String name, int level) {
        super(name);
        this.level = level;
    }

    public void thunderbolt() {
        System.out.println(name + " 使用了十万伏特！ 等级：" + level);
    }
}

class Eevee extends Pokemon {
    public Eevee(String name) {
        super(name);
    }

    public void adapt() {
        System.out.println(name + " 可以进化为多种形态！");
    }
}

public class Main {
    public static void main(String[] args) {
        Pokemon poke1 = new Pikachu("皮卡丘", 25); // 向上转型
        Pokemon poke2 = new Eevee("伊布");

        if (poke1 instanceof Pikachu) {
            Pikachu pika = (Pikachu) poke1; // 向下转型
            pika.thunderbolt();
        }

        switch (poke2) {
            case Pikachu p -> p.thunderbolt();
            case Eevee e -> e.adapt();
            default -> System.out.println("未知的宝可梦");
        }
    }
}
```

🧩 本章你学会了如何识别对象实际类型，并通过类型转换调用正确的技能！

---

# 🎭 第9章 一招多用！多态性的魔力

## 💡 9.1 方法重载（Overload）

### 🧠 “同一招式，不同效果”——方法重载的机制

在 Java 中，同名方法只要参数不同就可以共存。  
这就像“撞击（单人战）”和“撞击（双打战）”这样技能变种。

```java
public void attack(String move) {
    System.out.println("使用了「" + move + "」！");
}

public void attack(String move, int times) {
    System.out.println("连续使用了「" + move + "」" + times + "次！");
}
```

📝 方法名相同、参数不同即构成重载。

---

## 🔁 9.2 方法重写（Override）

### 🔄 “进化后技能强化”——方法重写的本质

方法重写是指子类覆盖父类的方法，以提供更具体的实现。

```java
public class Pokemon {
    public void attack() {
        System.out.println("普通攻击！");
    }
}

public class Pikachu extends Pokemon {
    @Override
    public void attack() {
        System.out.println("皮卡丘使用了十万伏特！");
    }
}
```

📝 `@Override` 注解可确保正确重写方法，避免拼写错误或签名不符。

---

## 🌀 9.3 多态性（Polymorphism）

### 🎨 “一招多效”——多态性的强大之处

**多态性** 指的是使用父类类型变量，调用实际子类中实现的方法。

```java
Pokemon poke1 = new Pikachu();
poke1.attack(); // 实际调用的是 Pikachu 的 attack()
```

📝 调用方法时依据“实际对象”类型执行，而不是变量声明的类型。

这称为“动态绑定”。

---

### ✨️ 提示：训练师操作示例

```java
public class Trainer {
    public void usePokemon(Pokemon p) {
        p.attack(); // 自动根据实际类型调用正确技能
    }
}
```

训练师无需知道宝可梦的具体种类，只需调用统一的接口。

---

## 🎯 9.4 总结与测试

### ✅ 第9章重点总结

| 概念         | 说明                                     |
|--------------|------------------------------------------|
| 重载（Overload） | 同名方法，参数不同                         |
| 重写（Override） | 子类覆盖父类方法                          |
| 多态（Polymorphism） | 父类变量调用子类方法，实现“统一接口多种行为” |
| 动态绑定     | 在运行时决定调用哪个方法                    |

---

### 💻 综合示例代码

```java
public class Pokemon {
    public void attack() {
        System.out.println("普通攻击！");
    }

    public void attack(String move) {
        System.out.println("使用了「" + move + "」！");
    }

    public void attack(String move, int times) {
        System.out.println("连续使用了「" + move + "」" + times + "次！");
    }
}

class Pikachu extends Pokemon {
    @Override
    public void attack() {
        System.out.println("皮卡丘使用了十万伏特！");
    }
}

class Eevee extends Pokemon {
    @Override
    public void attack() {
        System.out.println("伊布使用了星星闪光！");
    }
}

class Trainer {
    public void usePokemon(Pokemon p) {
        p.attack(); // 多态：调用子类实际实现的方法
    }
}

public class Main {
    public static void main(String[] args) {
        Trainer ash = new Trainer();

        Pokemon pika = new Pikachu();
        Pokemon eevee = new Eevee();

        ash.usePokemon(pika);   // 调用 Pikachu.attack()
        ash.usePokemon(eevee);  // 调用 Eevee.attack()

        pika.attack("铁尾");            // 方法重载
        pika.attack("电光一闪", 2);     // 方法重载
    }
}
```

🧩 通过本章，你已掌握方法重载、方法重写及多态性的实际使用方式！

---

# 🦄 第10章 幻之宝可梦的谜团！抽象类的世界

## 🧩 10.1 什么是抽象类

### 👻 “图鉴中未公开的神秘宝可梦”——抽象类的特征与作用

抽象类是“不完整的设计图”，不能直接实例化。  
需要通过子类实现其抽象方法后，才能使用。

```java
public abstract class Pokemon {
    String name;
    String type;

    public void introduce() {
        System.out.println("我是 " + name + "！类型是 " + type + "！");
    }

    public abstract void specialMove(); // 抽象方法：没有实现内容
}
```

📝 被 `abstract` 修饰的方法没有具体内容，必须由子类实现。

---

## 🧬 10.2 继承抽象类

### 🌟 “从神秘到现实”——抽象方法的实现技巧

继承抽象类时，子类必须实现所有抽象方法。

```java
public class Mew extends Pokemon {
    public Mew() {
        name = "梦幻";
        type = "超能力";
    }

    @Override
    public void specialMove() {
        System.out.println("梦幻使用了精神强念！");
    }
}
```

📝 抽象方法的实现必须与父类方法签名一致。

---

### ✨️ 提示：也可以将子类继续设为抽象类，让后代来实现具体行为

```java
public abstract class LegendaryPokemon extends Pokemon {
    public abstract void summon(); // 再次抽象化行为
}
```

---

## 🗺 10.3 抽象类的类图

### 🖼 “图鉴中的神秘页面”——抽象类的图形表达方式

```
<<abstract>> Pokemon
    +introduce()
    +specialMove() ← abstract

        ▲
        |
     Mew 实现了 specialMove()
```

📝 `<<abstract>>` 表示抽象类，三角箭头表示继承关系。

---

## 🎯 10.4 总结与测试

### ✅ 第10章重点总结

| 项目           | 内容                                     |
|----------------|------------------------------------------|
| 抽象类         | 无法实例化的类，需由子类补全              |
| 抽象方法       | 没有实现内容的方法，必须被子类覆盖实现    |
| 强制继承实现   | 含抽象方法的类，子类必须实现全部方法       |
| 中间抽象化设计 | 可以将继承链的中间类也设为抽象类          |

---

### 💻 综合示例代码

```java
public abstract class Pokemon {
    protected String name;
    protected String type;

    public void introduce() {
        System.out.println("我是 " + name + "，类型是 " + type + "！");
    }

    public abstract void specialMove(); // 抽象方法
}

class Mew extends Pokemon {
    public Mew() {
        this.name = "梦幻";
        this.type = "超能力";
    }

    @Override
    public void specialMove() {
        System.out.println(name + " 使用了精神强念！");
    }
}

public class Main {
    public static void main(String[] args) {
        Pokemon mystery = new Mew(); // 用父类类型声明对象
        mystery.introduce();         // 调用已实现的方法
        mystery.specialMove();       // 调用重写的抽象方法
    }
}
```

🧩 本章你学会了如何设计无法直接使用的抽象类，并通过子类完成其行为定义！

---
# 🔗 第11章 宝可梦的属性与能力！接口的力量

## 💡 11.1 什么是接口（interface）

### 🔍 “飞行属性”“水属性”——接口的定义与本质

Java 中的接口，就像宝可梦的“属性”一样，定义了某类宝可梦都必须具备的行为。

```java
public interface Flyable {
    void fly(); // 所有飞行宝可梦都必须实现飞行
}
```

📝 `interface` 是一种行为规范，只定义方法，不实现内容。

---

### 🧪 “拥有多种属性”类实现多个接口

```java
public class Charizard implements Flyable {
    @Override
    public void fly() {
        System.out.println("喷火龙飞上了天空！");
    }
}
```

📝 使用 `implements` 来声明类实现接口中的功能。

---

### ✨️ 提示：接口中的方法默认是 `public abstract`，不可更改访问级别

---

## 🔁 11.2 转换为接口类型

### 🔄 “作为飞行属性的宝可梦”——使用接口变量指向对象

```java
Flyable flyingPokemon = new Charizard();
flyingPokemon.fly();
```

📝 用接口类型声明变量，可以聚焦于行为而非具体实现。

---

### 🎯 “水属性攻击！”接口类型的更多使用方式

```java
public interface WaterType {
    void surf();
}

public class Vaporeon implements WaterType {
    @Override
    public void surf() {
        System.out.println("水伊布使用了冲浪！");
    }
}
```

---

## 🎭 11.3 接口实现多态性

### 🧬 “不同宝可梦，相同属性”——接口实现多态性

```java
public void useFly(Flyable f) {
    f.fly(); // 所有实现 Flyable 接口的对象都可以飞
}
```

📝 可以使用接口作为参数类型，实现不同类共享同一行为的调用。

---

### 🧪 “飞行动作一览”接口的统一调用演示

```java
Flyable f1 = new Charizard();
Flyable f2 = new Pidgeot();

f1.fly(); // 喷火龙
f2.fly(); // 比雕
```

---

## 🌐 11.4 接口继承接口

### 🔗 “混合属性的新种族”接口之间的继承

```java
public interface FlyingWaterType extends Flyable, WaterType {
    void dive();
}
```

📝 可以组合多个接口形成更复杂的行为集合。

---

### 🧠 “即使进化，属性也会保留”子类继承接口实现

```java
public class Gyarados implements FlyingWaterType {
    @Override
    public void fly() {
        System.out.println("暴鲤龙振翅高飞！");
    }

    @Override
    public void surf() {
        System.out.println("暴鲤龙使出了冲浪！");
    }

    @Override
    public void dive() {
        System.out.println("暴鲤龙潜入了深海！");
    }
}
```

---

## 🎯 11.5 总结与测试

### ✅ 第11章重点总结

| 项目         | 内容                                     |
|--------------|------------------------------------------|
| interface    | 行为规范，所有实现者必须遵循               |
| implements   | 实现接口行为                              |
| 多重实现     | 一个类可以实现多个接口                     |
| 接口多态     | 使用接口类型调用不同类的行为，实现多态      |

---

### 💻 综合示例代码

```java
public interface Flyable {
    void fly();
}

public interface WaterType {
    void surf();
}

public class Charizard implements Flyable {
    @Override
    public void fly() {
        System.out.println("喷火龙飞上了天空！");
    }
}

public class Vaporeon implements WaterType {
    @Override
    public void surf() {
        System.out.println("水伊布使用了冲浪！");
    }
}

public class Gyarados implements Flyable, WaterType {
    @Override
    public void fly() {
        System.out.println("暴鲤龙振翅高飞！");
    }

    @Override
    public void surf() {
        System.out.println("暴鲤龙使出了冲浪！");
    }
}

public class Main {
    public static void main(String[] args) {
        Flyable f = new Charizard();
        WaterType w = new Vaporeon();
        Flyable fw = new Gyarados();

        f.fly();
        w.surf();
        fw.fly();

        if (fw instanceof WaterType water) {
            water.surf(); // 使用暴鲤龙的 surf()
        }
    }
}
```

🧩 本章掌握了接口的定义、实现、组合、多态，以及如何设计拥有多重属性的宝可梦！