查漏补缺:别把继承当成语法糖,内存结构和权限边界才是重点

学到继承、封装和访问修饰符这一篇,很多人会觉得自己全懂了,无非是写个 extends、打个 private。但真到写代码或者排查报错时,又开始含糊:子类对象到底是怎么在内存里一步步搭起来的?父类构造方法为什么非得先走?protected 和默认包权限到底在什么场景下会出问题?这门课解决的就是这种“知道名词、说不清机制”的半桶水状态。它不满足于让你记住怎么写代码,而是逼你把对象创建时的内存结构、方法调用的绑定过程、以及权限修饰符的设计意图一次理清。如果你写 Java 时经常靠猜,或者看框架源码时一到继承链就卡壳,这一篇就是补这块底子的。

能力缺口与重点观看顺序

这门课适合已经能独立定义类、写构造方法、用基本类型和引用类型,但对“对象在内存里长什么样”还没建立直觉的人。如果你连 this 指向哪里都说不准,建议先补完前面的类与对象基础再来。看这份资料时,别从头到尾匀速过。建议先啃三块:第一是继承的内存结构,重点看子类对象实例化时,堆里是怎么按父类到子类的顺序逐层分配空间的,这是理解后续一切行为的地基;第二是重写与子类调用父类构造方法的逻辑,搞清楚为什么要保证父类初始化先完成,以及 super 在这里的实际作用;第三是 public、private 等权限修饰符的边界,别只背表格,要结合具体场景理解为什么默认包权限和 protected 在跨包时会表现不同。单例模式、最终类和组合代理那几块可以放在后面看,它们本质是前面概念的应用延伸。

配套练习与学完应能回答的问题

这份资料不能光看,必须配合动手。每看完一个内存结构的讲解,就自己写一段代码,在子类和父类的构造方法里都打印当前对象的哈希值,验证它们是不是同一个对象。看完重写后,写一个父类引用指向子类对象的例子,故意调用同名方法,观察实际执行的是哪个,再断点跟进去看调用链。权限修饰符那部分,自己建两个包,把类分别放进去,试一下把字段改成 protected 后跨包访问到底报不报错,别只听结论。对象数组的操作也别跳过,自己写一个对象数组,手动往里塞 null 和实例,体会空指针和越界是怎么产生的。资料里的单例模式实现要自己敲一遍,把构造方法私有化后,想想外部怎么拿实例,再问自己如果多线程同时访问会不会出问题,这个问题先留着,后面会专门解决。

学完这一篇,你应该能独立做几件事:画出一个子类对象创建时,堆内存里父类部分和子类部分是怎么叠放的,能说清构造方法的调用顺序为什么是固定的;给一个设计混乱的类,你能指出哪些字段该用 private 封装、哪些方法该暴露成 public,以及为什么某些方法要标记成最终方法防止被重写;看到 instanceof 判断时,你能解释它和直接类型转换的关系,知道什么时候该用它来避免强转报错;面对需求时,你能判断到底该用继承还是用组合,而不是无脑 extends。把这些缺口补上,你写出来的 Java 代码才不会总靠运气跑通,看别人的框架源码时也不至于在继承链前发懵。

课程目录

1 什么是继承,以及Object类 (15:43)
2 继承的内存结构 1 (20:24)
3 继承的内存结构2,以及单继承 (20:39)
4 重写 (27:31)
5 子类如何调用父类的构造方法 (16:00)
6 instanceof关键字 (16:25)
7 最终方法、最终类 (19:40)
8 单例模式 (17:15)
9 关键字总结,public、private等的权限1 (21:42)
10 public、private等的权限2 (17:13)
11 组合、代理、对象数组 (18:01)
12 操作对象数组 (21:00)