☕ 第四章 面向对象(下)

4.8 本章小结

📄 一句话概括

本章不写新知识点,只干一件事:把 4.1~4.7 七节拧成一股绳——从"extends 白得成员"出发,到 final 踩刹车、抽象类和接口定合同、多态统一调度、Object 收网万物之祖、内部类塞进类里、Lambda 把行为当参数传。至此面向对象三大特性全部点亮,面向对象阶段完结。


1. 七节串成一条线

4.1 继承        extends 白得非 private 成员;is-a 才继承;Object 万物之祖
  ↓
4.2 final       三把锁:变量锁值 / 方法锁重写 / 类锁继承(给扩展踩刹车)
  ↓
4.3 抽象类和接口 abstract 半成品图纸(不能 new);interface 纯合同(单继承+多实现)
  ↓
4.4 多态        三前提;编译看左运行看右;向下转型先 instanceof 验货
  ↓
4.5 Object类    toString 说人话;equals vs ==;字符串内容永远 equals
  ↓
4.6 内部类      四兄弟;成员内部类摸私房;匿名内部类 = 一次性实现
  ↓
4.7 函数式编程  函数式接口入场券;Lambda 三段式;匿名类的瘦身版

一条暗线贯穿全章:程序越来越灵活,变化越来越不费劲。 继承复用父类代码 → 接口把"能干什么"定成合同 → 多态让一个方法管一群对象 → Lambda 干脆把"一段行为"当参数传来传去。每次"更灵活",都是在给"将来会变的部分"留活口。


2. 核心概念速查(14 条,考前 3 分钟扫完)

# 概念 一句话
1 extends 继承 子类白得父类非 private 成员;Java 只支持单继承
2 is-a 口诀 "狗是动物"念得通才继承;"轮胎和汽车"是 part-of,念不通
3 final 三把锁 变量锁值、方法锁重写、类锁继承;final 引用不锁对象内容
4 static final 常量 全大写命名,编译期定死,如 Math.PI
5 abstract 抽象类 有抽象方法必须 abstract;不能 new;子类必须全兑现
6 interface 接口 纯合同:方法自动 public abstract,属性自动 public static final
7 单继承 + 多实现 类只能一个爹,合同能签多份;接口之间可以多继承
8 is-a vs can-do 抽象类管"是什么",接口管"能干什么"
9 多态三前提 继承 / 重写 / 父类引用指子类对象,缺一不可
10 编译看左运行看右 编译管安全(左边有什么才能调什么),运行管真实(右边的方法体干活);属性除外
11 向下转型 必须强制且先 instanceof 验货,否则 ClassCastException
12 Object 三件套 toString(默认"类名@乱码")、equals(默认就是 ==)、hashCode(搭伴规矩)
13 内部类四兄弟 成员(摸私房)/ 静态 / 局部 / 匿名(一次性实现)
14 函数式接口与 Lambda 有且只有一个抽象方法的接口;(参数) -> { 方法体 },单语句仨一起省

3. 代码模板速查(四段,背熟能救命)

① 继承 + 多态标准姿势

class Animal {
    public void sound() { System.out.println("动物叫"); }
}
class Dog extends Animal {                    // is-a:狗是动物
    @Override
    public void sound() { System.out.println("汪汪"); }
}

Animal a = new Dog();   // 父类引用指子类对象——多态第一前提
a.sound();              // 编译看左(Animal 有 sound),运行看右(狗汪汪)

② 接口 + 实现(合同必须全兑现,权限只能放宽)

interface Flyable {
    void fly();                               // 自动 public abstract
}
class Bird implements Flyable {
    @Override
    public void fly() { ... }                 // 必须写 public,少一个抽象方法都编译报错
}

③ 安全向下转型模板(先验货再转)

if (a instanceof Dog) {        // 先问一句"你是不是狗"
    Dog d = (Dog) a;           // 验过货再强转,不会炸
    d.guardHome();
}

④ 匿名内部类 vs Lambda(同一个功能的两种写法)

// 匿名内部类:接口方法多、或实现要用抽象类/普通类时
Flyable f1 = new Flyable() {
    @Override
    public void fly() { System.out.println("扑棱扑棱"); }
};

// Lambda:函数式接口(单抽象方法)专用,五行压一行
Flyable f2 = () -> System.out.println("扑棱扑棱");

4. 本章名坑回顾(七个,个个真会撞)

⚠️ 坑 1:final 引用不锁对象内容

final StringBuilder sb 里照样能 sb.append(...)——final 锁的是房产证不许过户(引用不换),家具随便挪(对象内容可改)。4.2 的 Q4 原题。

⚠️ 坑 2:实现接口方法忘写 public

接口方法自动是 public,实现类里"什么都不写"是默认权限——权限只能放宽不能收窄,直接编译报错。合同条款只会比你答应的更严格。

⚠️ 坑 3:成员变量没有多态

Animal a = new Dog(); a.name 用的是左边 Animal 的属性——方法看右边,属性两边都看左边。把"方法多态"推广到属性上是本章第一大陷阱。

⚠️ 坑 4:向下转型不验货

(Dog) a 之前不写 instanceof,一旦 a 实际是 Cat 就炸 ClassCastException——和空指针、数组越界并列三大新手异常。先验货,永远先验货。

⚠️ 坑 5:字符串比较用 ==

常量池让 "abc" == "abc" 碰巧是 true,new String("abc") == "abc" 就是 false——巧合不是规律。铁律只有一条:字符串内容永远用 equals。

⚠️ 坑 6:匿名内部类当可复用类用

每次 new Flyable() {...} 都是现场造一个新类——写三次就是三个类,而且没有名字没法单独测试。只用一次才匿名;用两次以上,建正经类。

⚠️ 坑 7:Lambda 省略只省一半

单语句省略时大括号、return、分号是一个套餐,-> return a + b; 这种半省不省直接编译报错。另外 Lambda 只认函数式接口——两个抽象方法的接口它管不了。

坑的规律:第一章的坑在工具层,第二章在逻辑层,本章的坑大多是"编译能过、运行才炸"或"编译报错但信息晦涩"——所以本章自测题反复强调:先验货(instanceof)、看报错原文、用编译器当裁判。


5. 面向对象收官:三大特性进度条

封装(3.3)✅ ──→ 继承(4.1)✅ ──→ 多态(4.4)✅

三章连起来看:封装把数据藏好、只留受控的门;继承把公共部分抽给父类、子类只写增量;多态让调用方只认父类/接口、不用关心具体是谁在干活。三者合起来才叫面向对象——缺一个,另外两个都白搭。

第四章在三大特性之外补齐了配套装备:final 和 abstract 是继承体系上的"刹车与图纸",Object 是所有类的公共底座,内部类和 Lambda 是把"实现"写得更省的进阶语法。从下一章起,进入"工具箱扩容"阶段——面向对象的思想会出现在每一个新 API 背后。


6. 与前面章节的连线(复习用)

本章知识点 承接哪篇 连的是什么
继承白得成员 3.2 类与对象 子类对象 = 父类部分 + 子类增量,全在一个堆格子里
接口属性三自动 4.2 final public static final 就是 4.2 三件套的接口自动版
多态"编译看左" 2.6 方法 方法签名(参数/返回值)从来都是编译期定规矩
Object toString 1.4 运行机制 println 的参数本质是 Object,万物可打
equals vs == 2.3 运算符 == 比地址(基本类型比值),equals 比内容(重写后)
Lambda 参数省类型 4.4 多态 "编译看左"第三次上岗:类型从左边接口签名推出来
匿名类 / Lambda 4.3 接口 接口定合同,匿名类/Lambda 是"现场兑现合同"的两种姿势

7. 毕业自检(5 题,合上笔记答)

❓ Q1:extends 和 implements 各解决什么问题?"单继承 + 多实现"为什么这样设计?

extends 解决代码复用(白得父类成员),implements 解决能力声明(签订能力合同)。单继承是因为两个爹可能给了冲突的实现(diamond 问题);多实现没这个风险——接口(老版本)只定合同不给实现,冲突无从谈起。

❓ Q2:`Animal a = new Dog(); a.sound(); a.name;` 各看哪边?

方法调用看右边(运行时是狗,汪汪);属性访问看左边(拿的是 Animal 里声明的 name)——属性没有多态,编译运行都看左。这是 4.4 最重要的特例。

❓ Q3:== 和 equals 的完整口径?字符串比较用什么?

==:基本类型比值,引用类型比地址。equals:Object 默认实现就是 ==(比地址),String 等类重写后比内容。字符串内容比较永远用 equals——== 的 true 只是常量池巧合,new 出来的就露馅。

❓ Q4:什么时候用匿名内部类,什么时候用 Lambda?

接口有多个抽象方法、或要现场实现抽象类/普通类 → 匿名内部类(必须全兑现)。接口是函数式接口(单抽象方法)且逻辑短 → Lambda(一行流)。Lambda 不是匿名类的替代品,是它的专用瘦身版。

❓ Q5(毕业大题):综合全章设计——抽象类 Animal(抽象方法 sound())、接口 Flyable(fly())、类 Bird extends Animal implements Flyable;写测试类用 `Animal[] zoo` 装狗、猫、鸟,循环喊叫;对会飞的用 instanceof + 向下转型喊 fly();最后用 Lambda 加一个 Runnable 开线程输出"起飞准备"。

要点自查:① Bird 必须同时兑现 sound() 和 fly() 且都写 public;② 数组循环是多态主场(编译看左运行看右);③ 转型前必须 instanceof 验货;④ Flyable 和 Runnable 都是函数式接口,Lambda 直接上岗。合格标准:不看笔记 30 分钟内编译运行通过;优秀标准:能指出哪几行靠封装、哪几行靠继承、哪几行靠多态。写不出就翻回 4.1 / 4.3 / 4.4 / 4.7,看完合上再写。


8. 下一步学什么


相关笔记