

為了讓廣大工程師們更好的提升個人技術能力和思想,我將開通一個大專欄《成長記》系列,會包含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 = https://www.cnblogs.com/fanmao/p/{};
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 發布
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/317456.html
標籤:Java
