主要内容:
第 1 章 基础
01 开篇词:为什么学习本专栏
不为了源码而读源码,只为了更好的实践
你好,我是文贺,Java 技术专家,DDD 和业务中台的资深实践者,一周面试 2~3 次的面试官。
说起自己开始阅读 Java 源码的契机,还是在第一年换工作的时候,被大厂的技术面虐的体无完
肤,后来总结大厂的面试套路,发现很喜欢问 Java 底层实现,即 Java 源码,于是我花了半年时
间,啃下了 Java 源码,终于进了网易。
以我个人经历来说,阅读源码真的可以帮助你顺利过技术面,找到更好的工作。
阅读源码还可以帮忙我们增加个人自信,学习其优良设计思想,总结出最优使用姿势,避免踩坑,
甚至针对工作中的痛点进行创新改造。
而在实际工作中,你可能遇到过这些尴尬:
1. 很多 API 的使用,需要先百度,然后再复制粘贴;
2. 针对不同的场景,不知道如何设计不同类型的线程池,对 API 的使用没有太多的场景经验总
结;
3. 代码 review 的时候,提不出意见,自己的代码却常常被别人吐槽;
4. 对于工作中 API 使用不方便的地方,想优化,但不知其内部实现原理,不敢动手。
通过调查发现,能绕过以上尴尬的同学,多数都是阅读过 Java 源码、对 Java 底层的构造了如指
掌的。这些同学能写团队核心代码,能轻易看出代码漏洞,能总结出 Java 的设计思想,并运用
到日常工作中。
所以说阅读 Java 源码,还能让我们结合场景熟练的使用 API,基于工作中使用痛点做一些源码
创新,是成为团队核心的技术基础。
我现在陆续阅读过 Java 7、8 的源码几遍,一开始很难坚持,因为源码比较枯燥。首先不知道源
码的整体架构,然后细节之处不知道为什么这么写,但最终还是啃下来了,甚至喜欢了阅读源码,
于是我在想,是不是可以把我的源码阅读经验和一线工作经验结合,使本课程成为源码的阅读指
南、面试指南和场景实战指南。
为了大家更易阅读,在接下来的 40 课中,我们会先从实际的案例场景出发,对 Java 中 30+ 个
核心类进行图文源码解析,并从中总结出设计思想、最优使用姿势和坑,最终以连环面试题进
行巩固。
我们对于每个源码类的文章套路为:
1. 怎么用:用场景来说明类的重要方法的使用技巧;
2. 为什么:源码解析其底层实现源码,复杂的源码会有动图解析;
3. 总结:总结出设计思想、最优使用姿势和坑,看看能否为工作中所用;
4. 面试题:总结出最新连环面试题,一题接着一题深入,可以作为面试官和面试者的面试指南。
本课程涉及到的 Java 知识非常齐全,主要有基础类、集合类、并发集合类、队列、线程、锁、
线程池、Lambda 流等内容,内容几乎涵盖了工作和面试的核心,如果你对这些源码都了如指掌,
面试题再千变万化,你也能应对自如。
源码解析主要以 Java 8 为主,对版本变动较大的类会做 Java 7、8 版本的比较。
学习本课程门槛较低,只需要你有一颗肯学习进步,希望成为 Java 技术专家的信心和决心即可。
本课程会有源码的 GitHub,欢迎喜欢阅读源码的同学来创建自己的分支,一起来结伴阅读源码,
写上自己的感悟互相交流。
总之,我一定会把专栏写的通俗易懂,也希望面前的你通过阅读本课程,找到更好的工作,走上
Java 专家之路,成为更专业,更资深,更有影响力的技术实践创新者。
02 String、Long 源码解析和面试题
引导语
String 和 Long 大家都很熟悉,本小节主要结合实际的工作场景,来一起看下 String 和 Long 的底
层源码实现,看看平时我们使用时,有无需要注意的点,总结一下这些 API 都适用于哪些场景。
1 String
1.1 不变性
我们常常听人说,HashMap 的 key 建议使用不可变类,比如说 String 这种不可变类。这里说的
不可变指的是类值一旦被初始化,就不能再被改变了,如果被修改,将会是新的类,我们写个
demo 来演示一下。
String s ="hello";
s ="world";
从代码上来看,s 的值好像被修改了,但从 debug 的日志来看,其实是 s 的内存地址已经被修改
了,也就说 s =“world” 这个看似简单的赋值,其实已经把 s 的引用指向了新的 String,debug 的
截图显示内存地址已经被修改,两张截图如下:
我们从源码上查看一下原因:
public final class String
implements java.io.Serializable, Comparable, CharSequence {
/** The value is used for character storage. */
private final char value[];
}
我们可以看出来两点:
1. String 被 final 修饰,说明 String 类绝不可能被继承了,也就是说任何对 String 的操作方法,
都不会被继承覆写;
2. String 中保存数据的是一个 char 的数组 value。我们发现 value 也是被 final 修饰的,也就是
说 value 一旦被赋值,内存地址是绝对无法修改的,而且 value 的权限是 private 的,外部绝
对访问不到,String 也没有开放出可以对 value 进行赋值的方法,所以说 value 一旦产生,
内存地址就根本无法被修改。
以上两点就是 String 不变性的原因,充分利用了 final 关键字的特性,如果你自定义类时,希望
也是不可变的,也可以模仿 String 的这两点操作。
因为 String 具有不变性,所以 String 的大多数操作方法,都会返回新的 String,如下面这种写法
是不对的:
String str ="hello world !!";
// 这种写法是替换不掉的,必须接受 replace 方法返回的参数才行,这样才行:str =
str.replace("l","dd");
str.replace("l","dd");