JDK源码阅读笔记:html
如何阅读源码,是每一个程序员须要面临的一项挑战。git
为何须要阅读源码?从实用性的角度来看,主要有三个目的:第一,解决手头的新问题或者新需求;第二,真正理解一部分理论的落地实现;第三,应对面试。程序员
在准备投身到阅读源码的事业以前,首先须要端正一下心态:github
在此,我更推荐把源码阅读当成是一项兴趣爱好去作,就比如有的人经过打游戏看直播放松,有的人经过刷新闻追热剧放松,还有的人经过找朋友吹牛逼放松...不一样的人会选择不一样的劳逸结合方式,我更喜欢不写代码的时候,经过看别人的代码来放松。面试
做为一名Javaer,朝夕相处的JDK天然是你遇到的第一处宝藏之地。从阅读JDK代码出发,能够深刻理解Java的一些新老特性,并学习部分设计模式的应用,以及为未来阅读更庞大的框架打下扎实的理论基础与顽强的心理基础。正则表达式
工欲善其事必先利其器,起步以前,须要先选择一款源码阅读工具。在工具的选择上,同行的建议不少,我大体将其分为四类:算法
文本型工具(该分类可能会有争议,不过这不是重点...)
例如Nodepad++、EditPlus、UEStudio、Sublime、VsCode、Vim等sql
专家型工具
例如Source Insight、Understand、OpenGrok(也是不少在线工具的基石)等编程
在线工具(好几个在线网站已经挂了)
例如openjdk、SearchCode等
IDE
例如eclipse/myeclipse、IDEA等
从我的喜爱讲,我推荐IDEA和UEStudio(搭配UltraFinder)配合使用。
IDEA做为强大的Java生产工具,用来阅读Java源码显然再合适不过。而UEStudio能够做为临时查看Java文件或者查看JDK中部分C++代码时的选择,再搭配UltraFinder,实现跨文件的任意符号搜索,很实用。
关于阅读环境的搭建,参见我在https://github.com/kangjianwei/LearningJDK中的描述便可。
JDK的项目历经了十几个大版本,算上开源社区的贡献,经手的人可能也达到上千人。对于这种庞大的项目,一次性读完确定是不可能,必须先找到一个恰当的入口,分模块来一点点啃完。
可能的一种阅读顺序是:
基本类型的包装类(Character放在最后)
String、StringBuffer、StringBuilder、StringJoiner、StringTokenizer(补充正则表达式的知识)
CharacterIterator、StringCharacterIterator、CharsetProvider、CharsetEncoder、CharsetDecoder(较难)
java.util.function下的函数表达式
java.nio下的各类Buffer实现
java.lang.ref和jdk.internal.ref下的各类引用:软引用/弱引用/虚引用
Unsafe的实现(JDK9以后有两个同名类,一个引用了另外一个,建议放在一块儿阅读)
java.util.stream下的流式编程的实现(很难)
Thread和ThreadLocal
Math、Random、BigInteger、BigDecimal
java.lang.reflect下反射的实现(先掌握JDK 9以后引入的模块系统)
ClassLoader的实现
javax.lang.model下Java语言模型的实现(能够参考Java官方语法文档)
注解(须要完全掌握)
Timer、ResourceBundle、Properties
时间日期类型(尤为是Java8新增的部分)
java.lang.reflect.Proxy, JDK默认的动态代理
java.util.concurrent并发包。先读原子类,再读锁的实现类,最后阅读那些并发工具的实现(很难)
集合框架,主要是三大类:List、Set、Map(先读非线程安全的实现,再读线程安全的实现)
网络编程(主要阅读Socket通讯部分,后续能够阅读HttpClient的实现)
IO,包含BIO/NIO/AIO(很难)
Files、Path等文件操做工具类
sql、xml处理类/接口
......
注意,这里说的顺序只是一个大体的方向,并不表明须要绝对按照这个名单来。
在阅读某一个代码时,每每会牵涉到不少别的代码,这个时候就会产生不少阅读分支,分支的走向,并不在上述名单以内。
阅读代码的技巧,因人而异。就像一千位读者,就有一千部哈姆雷特,每一个人对这件事的见解并不相同。在此,我只谈下我的的一些经验。
理论先行。阅读某一个模块时,先搜索它的理论支撑,甚至能够先看别人的阅读经验,有了一个大体的了轮廓以后,本身再去实践。
必须试用。面对一个新的类,最好是先搜索一下它的基本用法,写成一个小的示例,并从这个示例中用到的方法入手,去分析这个类。
巧用调试。关于IDEA中debug的使用方式,超出了本文的讲述范围。值的注意的是,除了须要学习经常使用的运行时调试,还须要学习编译时调试,这个在阅读Java语言模型那块的代码时颇有用。
分清主次。类与类之间呈网状结构,在阅读某个类的时候,不可避免地须要先去阅读它引用的其余类。可是,若是它引用的类很复杂,则建议先放一放,作个标记,回头再读。不过,若是在阅读多个类时,其调用链最终都指向了同一个类,那么这个类就必须先拿下了。
业务为先。若是一个类太过庞大,则先将其中的方法按功能归类,捋清大体的执行流程,接下来再逐个功能地去攻克。
不求甚解。有些方法不须要搞清楚实现过程,只须要了解它的做用。好比一些特定领域的算法,对某些规则的解析等。
以点带面。若是看懂了某一个方法,就要搜索该方法的全部应用之处,验证本身的想法是否正确,并在应用之处写下注释。哪怕理解的有偏差也没事,回头有新的理解再批量修改。对于字段的阅读与理解,也建议采起此种方式。
敢于试错。不少接口方法的描述很抽象,在不一样的实现类中意义相差很大。此时先弄懂一个类的实现,而后拿着在这个类中的理解去解读另外的实现类,若是解读有误,再逐渐修复。不要期望一次性就能正确地理解某个方法的做用,理解错误,不妨碍继续前进。
留意注释。大部分公开的方法上都有相应的注释,这是快速理解这个方法的重要途径。注释建议拿到谷歌翻译下去阅读,固然,若是能流利阅读英文就更好了。不过,不少时候,注释是使人沮丧的:看完以后彻底不知道他在说啥。这个也很正常,由于有些注释中会涉及到不少行业术语或通用解决方案的描述,若是以前没有这些理论背景,大几率是读不懂注释的。原生注释不是万能的,有时候甚至很鸡肋:你不理解这个方法以前,也不理解他的注释,等你理解了这个方法,才会以为这些注释说得对。所以,我建议留意注释,但别依赖注释,有时候搜索其余网友的理解,再结合本身的阅读,会来的更舒服一些。
勤作笔记。有一点灵感,就须要记录一下,最好是直接记录在源码对应的位置,并且能详细就别简略,好记性终究抵不过烂笔头。
按部就班。在头脑清醒的时候,打开源码读一读,感受读不懂的时候,就不要继续死磕了,应该放下干点别的,或者改天再读。我读完一个类,时间跨度可能会超过一个月,这是个不断补充和完善的过程,不可能一次性就搞定。有时候眼看就读懂了,但就是差一点点关键性的理解,这个时候人就容易急,急就容易燥,燥就容易慌,慌就容易乱,乱就容易砸鼠标。因此,一旦以为遇到瓶颈,那就及时终止吧,由于你可能须要放松大脑,以及补充一些缺失的基础理论了。