为了让宽广工程师们更好的晋升集体技术能力和思维,我将开明一个大专栏《成长记》系列,会蕴含 Java 架构和大数据从底层技术到源码原理的分享,敬请关注!
无论作为 Java 程序员还是大数据工程师的你,工作工夫久了,可能很多底层和根底技术曾经还给你的大学老师或者 80% 曾经丢在脑后了。比方你可能曾经不记得网络模型有几层?TCP 三次握手,四次挥手的流程你可能也说不上来了?JDK 汇合和并发包的源码你可能压根没有看过,又或者很早之前你看过,但不记得了。甚至并发包下很多货色都没有用过。你也可能正在筹备跳槽或者面试,被各种根底虐过,又或者你看某个技术框架的源码艰涩难懂,无从动手……
或多或少你可能都遇见过这样的场景,所以在这个成长记系列中,就是让你解决这些问题。我不仅会教你学会这些底层和基础知识,解决下面这些问题,成长记更重要的外围是:除了给你带来能力、常识、办法的成长,更重要的是观点和心态的成长。所以你能够在每一个专栏中学习到很多观点、思维,这将耳濡目染的晋升你的认知,让你失去的不仅仅是“鱼”,更是会失去“渔”。
作为《成长记》的第一个专栏,《JDK 成长记》这篇专栏次要让你把握以下三点:
- JDK 的源码中汇合和并发包下的各种类的底层原理,跳槽面试遇见这块常识不再心虚。
- 在应用 JDK 汇合和并发时,能更得心应手,能更好的解决遇见的各种线上问题。
- 更次要的是让你学会根本的浏览源码的思维。
作为程序员的咱们,其实建造了整个社会计算机技术的底层零碎。然而,除此之外,你更要建设本人思想观念的底层零碎,这个底层零碎不仅会对你技术能力的晋升和职业倒退有帮忙,更会帮忙你的生存,乃至整个人生变得更美妙。而每个人的底层零碎都不尽相同,所以都须要一直的修改、一直的夯实。这个是《成长记》给你们的另一种成长。追随《成长记》的各个专栏,置信你将学到的不仅仅是常识和技能,还会有更多的思维和观点。
好了,接下来,就让咱们进入 JDK 源码的大门吧!
作为 Java 工程师,ArrayList 你应该十分相熟。当你还是一个菜鸟 Java 工程师的时候,面试时你可能常常被问到:你能说说 ArrayList 的基本原理和优缺点吗?它默认容量大小是多少呢?怎么进行扩容的呢?诸如此类,不晓得各位当初是怎么答复的。或者可能你曾经是一名老鸟的工程师了,是不是也常遗记给 ArrayList 设置容量大小。又或者老鸟的你可能要跳槽了,所以让咱们一起回顾下 ArrayList 的基础知识吧!
ArrayList 基本原理
一句话讲,在 JDK 中,ArrayList 底层基于一个 Object[]数组来保护数据。
ArrayList 优缺点
毛病:
- 容量受限时,须要进行数组扩容,进行元素拷贝会影响性能
- 频繁删除和往两头插入元素时,产生元素移动,也会进行元素拷贝,影响性能
- 不是线程平安的
长处:
- 随机拜访某个元素,性能很好
倡议:
保护程序插入的数据,遍历或者索引拜访很不便,预估数据大小,防止频繁扩容。不适宜频繁的删除和两头插入等操作和多线程操作。
你回顾了 ArrayList 的根本的原理和优缺点后,各位最好能够本人跟他人茶余饭后的聊一聊,问下他,这个问题,或者你给他讲讲,来坚固下这个基础知识。
接下来,你就能够开始看 ArrayList 的源码了,在看之前,你要先理解下看源码的最根本的一条思维。
当你关上源码,必定不是间接就开始从头开始看一遍,这样会一头雾水,所以必定是有思路和办法可寻的。
在这里,首先你要明确,看外围源码和精读源码的形式不太一样。看外围源码,也就是外围局部的源码,个别也就是 10-30%。你应该都是从一些入口开始看起,然而如果你要精读源码,除了在浏览外围源码的根底上,你还须要将源码拆解开来,钻研每一个组件的各个作用,之后再从入口开始,一行一行都读懂。
这其实体现了一个很重要的思维,无论做什么事,先摸脉络,后看细节。就比方瞎子摸象一样,你每个部位摸了一遍,然而没有全局的意识,这就很搞笑了。所以个别你应该先看外围源码再精读源码。
除了下面的思路,读源码其实还有很多技巧和办法,这个见仁见智,在这个成长记中置信你也会学到很多。然而有一点我要跟大家说的是,你可能在网上看到有很多 diss 这个看源码形式,那个看源码形式,也有各个博客,论坛各种形形色色的形式看源码。所以很多时候,你肯定要透过景象看实质,其实看源码的办法和技巧,没有优劣之分,这要围绕你的指标和场景来具体决定,抉择适合的形式才是最好的。你想下,很多事件都是不是这样的?大家不能一概而论,这个思维很重要,你要学会要站到肯定高度看问题,别总是陷入问题自身。
依据我的教训和理解到的各个浏览源码的办法,你能够在本章结尾看到总结。
看源码前,依照之前提到,你应该 先看脉络,再看细节。
比方,当你看 ArrayList 的源码,能够先看看它有哪些核心成员变量,刚开始,你必定不晓得哪些是外围的变量,所以简略过一下即可,依据名字,类型,大略看看即可,看不懂也没关系。之后看下有哪些办法,依据名字大略猜猜是做什么的。做这些次要让你理解根本的脉络,对源码有个大体映象,千万不要在这里细究源码。
在 Intellij 或 Eclipse 下,如果是应用 eclipse 快捷键的话,你能够通过 Ctrl+ O 看到这个类的大体状况:
这里,你次要有哪些办法和成员变量、外部类就能够了。
比方,你能够看到 ArrayList 源码中,有几个动态成员,从名字上看像是容量大小相干的,还有 size 和 elementData 等成员变量,有几个构造函数,
有一些 ensureCapacity,calculateCapacity 等公有办法,感觉也是和容量大小无关的。因为 Capacity 就是容量,大小的意思。还有很多你应该罕用的办法 add(),set(),get()等等。
最初上面,还有几个外部类 SubList 和 Itr 和 ListItr 什么的,如下图所示:
好了,其实你看到这里就能够了,起码对 ArrayList 的源码有了个大略意识,这就是 先脉络后细节 的思维体现。
之前咱们提到过,看外围源码个别是从入口开始,也就常说的自顶而下。
首先你要有个代码 Demo。之后从它的入口开始看起,代码清单如下:
import java.util.List;
public class ArrayListDemo {public static void main(String[] args) {List<String> list = new ArrayList<>();
}
}
这个很简略的代码,入口是 main 函数,第一行就是创立了一个 ArrayList,外面的元素都是 String 类型,应用默认无参的构造函数,你点击构造函数,进入源码来看看:
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData;private int size;
public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}
能够看到,有一个成员变量叫 elementData 的 Object[]数组,这个印证了咱们之前提到过的 ArrayList 底层基本原理是数组。而且你记不记得之前,在看 ArrayList 源码脉络的时候是不是曾经看到过了这个变量呢?
默认无参的构造函数让 elementData 指向了和空数组 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 一样的地址。
如果各位如果有印象的话,DEFAULTCAPACITY_EMPTY_ELEMENTDATA 这个变量也是你之前看到过的动态成员变量。
下面还列了一个成员变量 size,你能够 连蒙带猜 一下,它应该是形容数组大小的变量。而且 size 是 int 类型,大家都晓得 int 的默认值是 0。
所以小结一下,你晓得了 new ArrayList<>()这个动作,底层是应用了 Object[]数组,然而这个数组默认是空的,大小为 0。
下面咱们次要通过看脉络,连蒙带猜的思维,看了一个简略的不能再简略的源码。不晓得你有没有感觉到这两个思维。有了初步的感触。接下来我还要引入一个十分要害的办法:画图。
其实在我看来,没有什么算法不能用画图和举例了解的,起码个别大多数算法都能够了解的,小灰算法图解微信公众号就是最好的例子。在浏览源码的时候也是,画图能更好的了解源码,能让咱们站在高处,高屋建瓴的摸清楚源码的脉络,也能梳理进去次要思路,让咱们去更好的浏览源码。所以大家不能漠视了,再简略的场景,也要养成这个画图这个思路习惯。
下面 ArrayList 的无参构造函数的源码,基本上如下图所示:
好了,明天常识就分享到这里,下一节咱们来根本的应用一下 ArrayList,调用它的几个罕用办法,再来看看它罕用办法的源码和原理。前几节的节奏我会尽量慢一些,大家不要焦急,前面会越来越精彩!
持续往后看有彩蛋哟~
首先说源码的获取,个别以下几种
- 下载源码导入 Intellij 等 IDE,来浏览代码
- 开启 Maven 主动下载源码的性能
- 本人从官网(如 Github)或者 Maven 仓库手动下载源码
这几种都能够获取到源码,各有各的实用场景,比方如果你想写些正文,就须要导入到 IDE 才行,比方你想 Debug 源码,不须要把源码导入到 IDE 中,实用 2,3 的办法都能够。又比方有些代码 Maven 仓库基本没有,只能从 Github 或官网下载了。
其次,咱们聊下,浏览动态源码还是动静源码?这个取决于源码的复杂程度、你浏览源码的能力等。如果是一些简略的源码或者你有很多浏览源码的教训了,个别浏览动态源码就足够了。然而如果是小白,或者真的源码比较复杂,又或者你须要具体看看执行过程中的某个变量和返回值,你必定须要 debug 进行动静源码浏览了。
浏览源码的技巧,说白了就是一些思维,常见的有:
- 自顶而下或自底而上
- 抓大放小
- 先脉络,后细节
- 连猜带蒙
- 联合性能场景一一剖析
办法就更多了,次要有:
- 看正文
- 加正文
- 画图
- Debug
- 察看日志或减少日志
- ……
下面这些,之后我都会带大家应用到的,并且你会学会在适合的场景应用上,你只有继续关注成长记就能够了。
最初,还要说一点,有人说浏览源码,须要很多技术根底,确实没错。然而也分是什么样的源码,如果只是简略的源码,须要的基础知识会很少,比方 JDK 的源码。然而如果比拟难的源码,Zookeeper、HDFS、Kafka、Dubbo 这些源码,就须要把握 Netty,NIO,网络,Java 汇合和并发等根底能力看得更好。当然如果没有这些根底也不是不能看的,就是了解可能不会深,对源码最初可能只是初步理解。所以还是那句话,不要一概而论。
本文由博客一文多发平台 OpenWrite 公布!