JDK成長記1:天吶!學完這個成長記,再面試100次,也不用再愁Java基礎知識了!


file

file

為了讓廣大工程師們更好的提升個人技術能力和思想,我將開通一個大專欄《成長記》系列,會包含Java架構和大數據從底層技術到源碼原理的分享,敬請關注!

無論作為Java程序員還是大數據工程師的你,工作時間久了,可能很多底層和基礎技術已經還給你的大學老師或者80%已經丟在腦后了。比如你可能已經不記得網絡模型有幾層?TCP三次握手,四次揮手的流程你可能也說不上來了?JDK集合和並發包的源碼你可能壓根沒有看過,又或者很早之前你看過,但不記得了。甚至並發包下很多東西都沒有用過。你也可能正在准備跳槽或者面試,被各種基礎虐過,又或者你看某個技術框架的源碼晦澀難懂,無從入手……

或多或少你可能都遇見過這樣的場景,所以在這個成長記系列中,就是讓你解決這些問題。我不僅會教你學會這些底層和基礎知識,解決上面這些問題,成長記更重要的核心是:除了給你帶來能力、知識、方法的成長,更重要的是觀念和心態的成長。所以你可以在每一個專欄中學習到很多觀念、思想,這將潛移默化的提升你的認知,讓你得到的不僅僅是 “魚”,更是會得到“漁”。

作為《成長記》的第一個專欄,《JDK成長記》這篇專欄主要讓你掌握以下三點:

  1. JDK的源碼中集合和並發包下的各種類的底層原理,跳槽面試遇見這塊知識不再心虛。
  2. 在使用JDK集合和並發時,能更得心應手,能更好的解決遇見的各種線上問題。
  3. 更主要的是讓你學會基本的閱讀源碼的思想。

作為程序員的我們,其實建造了整個社會計算機技術的底層系統。但是,除此之外,你更要建立自己思想觀念的底層系統,這個底層系統不僅會對你技術能力的提升和職業發展有幫助,更會幫助你的生活,乃至整個人生變得更美好。而每個人的底層系統都不盡相同,所以都需要不斷的修正、不斷的夯實。這個是《成長記》給你們的另一種成長。跟隨《成長記》的各個專欄,相信你將學到的不僅僅是知識和技能,還會有更多的思想和觀念。

好了,接下來,就讓我們進入JDK源碼的大門吧!

file

file

file

作為Java工程師,ArrayList你應該非常熟悉。當你還是一個菜鳥Java工程師的時候,面試時你可能經常被問到:你能說說ArrayList的基本原理和優缺點嗎?它默認容量大小是多少呢?怎么進行擴容的呢?諸如此類,不知道各位當初是怎么回答的。或者可能你已經是一名老鳥的工程師了,是不是也常忘記給ArrayList設置容量大小。又或者老鳥的你可能要跳槽了,所以讓我們一起回顧下ArrayList的基礎知識吧!

ArrayList基本原理

一句話講,在JDK中,ArrayList底層基於一個Object[]數組來維護數據。

ArrayList優缺點

缺點:

  1. 容量受限時,需要進行數組擴容,進行元素拷貝會影響性能

  2. 頻繁刪除和往中間插入元素時,產生元素挪動,也會進行元素拷貝,影響性能

  3. 不是線程安全的

優點:

  1. 隨機訪問某個元素,性能很好

建議:

維護順序插入的數據,遍歷或者索引訪問很方便,預估數據大小,避免頻繁擴容。不適合頻繁的刪除和中間插入等操作和多線程操作。

你回顧了ArrayList的基本的原理和優缺點后,各位最好可以自己跟別人茶余飯后的聊一聊,問下他,這個問題,或者你給他講講,來鞏固下這個基礎知識。

接下來,你就可以開始看ArrayList的源碼了,在看之前,你要先了解下看源碼的最基本的一條思想。

file

file

當你打開源碼,肯定不是直接就開始從頭開始看一遍,這樣會一頭霧水,所以肯定是有思路和方法可尋的。

在這里,首先你要明白,看核心源碼和精讀源碼的方式不太一樣。看核心源碼,也就是核心部分的源碼,一般也就是10-30%。你應該都是從一些入口開始看起,但是如果你要精讀源碼,除了在閱讀核心源碼的基礎上,你還需要將源碼拆解開來,研究每一個組件的各個作用,之后再從入口開始,一行一行都讀懂。

這其實體現了一個很重要的思想,無論做什么事,先摸脈絡,后看細節。就比如瞎子摸象一樣,你每個部位摸了一遍,但是沒有全局的認識,這就很搞笑了。所以一般你應該先看核心源碼再精讀源碼。

file

除了上面的思路,讀源碼其實還有很多技巧和方法,這個見仁見智,在這個成長記中相信你也會學到很多。但是有一點我要跟大家說的是,你可能在網上看到有很多diss這個看源碼方式,那個看源碼方式,也有各個博客,論壇各種五花八門的方式看源碼。所以很多時候,你一定要透過現象看本質,其實看源碼的方法和技巧,沒有優劣之分,這要圍繞你的目標和場景來具體決定,選擇合適的方式才是最好的。你想下,很多事情都是不是這樣的?大家不能一概而論,這個思想很重要,你要學會要站到一定高度看問題,別總是陷入問題本身。

根據我的經驗和了解到的各個閱讀源碼的方法,你可以在本章結尾看到總結。

file

看源碼前,按照之前提到,你應該先看脈絡,再看細節

比如,當你看ArrayList的源碼,可以先看看它有哪些核心成員變量,剛開始,你肯定不知道哪些是核心的變量,所以簡單過一下即可,根據名字,類型,大概看看即可,看不懂也沒關系。之后看下有哪些方法,根據名字大概猜猜是做什么的。做這些主要讓你了解基本的脈絡,對源碼有個大體映象,千萬不要在這里細究源碼。

在Intellij或Eclipse下,如果是使用eclipse快捷鍵的話,你可以通過Ctrl+O看到這個類的大體情況:

file

這里,你主要有哪些方法和成員變量、內部類就可以了。

比如,你可以看到ArrayList源碼中,有幾個靜態成員,從名字上看像是容量大小相關的,還有size和elementData等成員變量,有幾個構造函數,

有一些ensureCapacity,calculateCapacity等私有方法,感覺也是和容量大小有關的。因為Capacity就是容量,大小的意思。還有很多你應該常用的方法add(),set(),get()等等。

最后下面,還有幾個內部類SubList和Itr和ListItr什么的,如下圖所示:
file

好了,其實你看到這里就可以了,起碼對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的無參構造函數的源碼,基本上如下圖所示:

file

好了,今天知識就分享到這里,下一節我們來基本的使用一下ArrayList,調用它的幾個常用方法,再來看看它常用方法的源碼和原理。前幾節的節奏我會盡量慢一些,大家不要着急,后面會越來越精彩!

繼續往后看有彩蛋喲~

file

首先說源碼的獲取,一般以下幾種

  1. 下載源碼導入Intellij等IDE,來閱讀代碼
  2. 開啟Maven自動下載源碼的功能
  3. 自己從官方(如Github)或者Maven倉庫手動下載源碼

這幾種都可以獲取到源碼,各有各的適用場景,比如如果你想寫些注釋,就需要導入到IDE才行,比如你想Debug源碼,不需要把源碼導入到IDE中,適用2,3的方法都可以。又比如有些代碼Maven倉庫根本沒有,只能從Github或官方下載了。

其次,我們聊下,閱讀靜態源碼還是動態源碼?這個取決於源碼的復雜程度、你閱讀源碼的能力等。如果是一些簡單的源碼或者你有很多閱讀源碼的經驗了,一般閱讀靜態源碼就足夠了。但是如果是小白,或者真的源碼比較復雜,又或者你需要具體看看執行過程中的某個變量和返回值,你肯定需要debug進行動態源碼閱讀了。

閱讀源碼的技巧,說白了就是一些思想,常見的有:

  • 自頂而下或自底而上

  • 抓大放小

  • 先脈絡,后細節

  • 連猜帶蒙

  • 結合功能場景逐個分析

方法就更多了,主要有:

  • 看注釋

  • 加注釋

  • 畫圖

  • Debug

  • 觀察日志或增加日志

  • ……

上面這些,之后我都會帶大家使用到的,並且你會學會在合適的場景使用上,你只要持續關注成長記就可以了。

最后,還要說一點,有人說閱讀源碼,需要很多技術基礎,的確沒錯。但是也分是什么樣的源碼,如果只是簡單的源碼,需要的基礎知識會很少,比如JDK的源碼。但是如果比較難的源碼,Zookeeper、HDFS、Kafka、Dubbo這些源碼,就需要掌握Netty,NIO,網絡,Java集合和並發等基礎才能看得更好。當然如果沒有這些基礎也不是不能看的,就是理解可能不會深,對源碼最后可能只是初步了解。所以還是那句話,不要一概而論。

本文由博客群發一文多發等運營工具平台 OpenWrite 發布


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM