Java集合中的ArrayList

? ? ? ? 今天我們來(lái)聊聊Java集合中的ArrayList,說(shuō)起集合在我們編碼過(guò)程中使用頻率最高的了。這一點(diǎn)大家沒(méi)有異議吧糜芳,接下來(lái)我們由淺入深逐步認(rèn)識(shí)一下ArrayList塘辅。

1.Java集合的設(shè)計(jì)


設(shè)計(jì)層次
繼承接口

? ? ? ? 上圖是Java集合的設(shè)計(jì)層次和java類繼承接口列表键耕,Java設(shè)計(jì)策略先由接口定義集合應(yīng)該具有的功能棚亩,接口設(shè)計(jì)完成后在具體類中實(shí)現(xiàn)具有這些功能的類。另外java集合提供了Collections工具類虏杰,它已經(jīng)實(shí)現(xiàn)了對(duì)集合排序讥蟆,遍歷等算法,我們可以使用它纺阔,快速的完成集合的排序瘸彤、遍歷等功能。同樣我們今天要聊到的ArrayList他繼承List笛钝,擁有Collection接口定義的功能质况,同樣可以使用Collections工具類對(duì)集合進(jìn)行排序、遍歷等玻靡。

2.ArrayList源碼分析

? ? ? ? 關(guān)于ArrayList的原理结榄,通過(guò)查看package java.util.ArrayList實(shí)現(xiàn),下面截圖部分是ArrayList的兩個(gè)構(gòu)造方法囤捻,一個(gè)是無(wú)參數(shù)一個(gè)是帶有長(zhǎng)度參數(shù)構(gòu)造方法的代碼臼朗,閱讀代碼我們可以發(fā)現(xiàn)ArrayList的底層是基于一個(gè)Object數(shù)組實(shí)現(xiàn)的。


ArrayList無(wú)參構(gòu)造函數(shù)
ArrayList帶有長(zhǎng)度的參構(gòu)造函數(shù)

? ? ? ? 既然知道了ArrayList底層是數(shù)組,故ArrayList擁有數(shù)組同樣特性视哑,比如可以通過(guò)索引獲取指定位置的數(shù)據(jù)绣否,也可以使用indexOf找到某個(gè)對(duì)象的索引位置。既然是數(shù)組在初始化創(chuàng)建對(duì)象的時(shí)候必須指定長(zhǎng)度挡毅。


ArrayList默認(rèn)長(zhǎng)度


3.ArrayList擴(kuò)容原理

? ? ? ? 源碼中指定ArrayList的默認(rèn)初始大小為10的數(shù)組蒜撮,長(zhǎng)度為10的Object數(shù)組很容易就裝滿了,如果增加的元素個(gè)數(shù)超過(guò)了10個(gè)慷嗜,那么ArrayList底層會(huì)新生成一個(gè)數(shù)組淀弹,長(zhǎng)度為原來(lái)數(shù)組的1.5倍+1,然后將原數(shù)組的內(nèi)容復(fù)制到新數(shù)組中庆械,并且后續(xù)增加的內(nèi)容都會(huì)放到新數(shù)組當(dāng)中薇溃,當(dāng)新數(shù)組無(wú)法容納增加的元素時(shí),重復(fù)該過(guò)程缭乘。下圖可以看到ArrayList擴(kuò)容過(guò)程


ArrayList擴(kuò)容過(guò)程

? ? ? ? JVM操作自動(dòng)擴(kuò)容的時(shí)候非常消耗性能沐序,所以在選取使用ArrayList的時(shí)候最好事先估算一下它的長(zhǎng)度,然后創(chuàng)建對(duì)象的時(shí)候傳入估算的值堕绩。盡量避免ArrayList自動(dòng)擴(kuò)容策幼,也有人會(huì)這樣考慮,初始化ArrayList指定一個(gè)足夠大的數(shù)據(jù)奴紧,雖然避免的自動(dòng)擴(kuò)容特姐,但是造成內(nèi)存的浪費(fèi)。ArrayList既然是事先分配的數(shù)組黍氮,分配的數(shù)組每個(gè)項(xiàng)的長(zhǎng)度是固定的唐含,那么如何使用ArrayList存放復(fù)雜的對(duì)象呢?

4.ArrayList數(shù)據(jù)存儲(chǔ)原理

? ? ? ? ArrayList是一個(gè)Object數(shù)組沫浆,如果ArrayList存放基本類型捷枯,可以直接存放到數(shù)組中,但使用ArrayList存放對(duì)象专执,事先分配的Object無(wú)法存放形式和大小各異的對(duì)象淮捆,那么ArrayList進(jìn)行了優(yōu)化,在ArrayList集合中存放的是對(duì)象的引用本股,而不是對(duì)象本身攀痊。


ArrayList存儲(chǔ)對(duì)象

? ? ? ? ArrayList巧妙的使用存對(duì)象引用的方法解決了復(fù)雜對(duì)象的存取問(wèn)題,這樣的設(shè)計(jì)類似C++的指針拄显,存取的索引地址可以方便方位索引位置的對(duì)象信息蚕苇。

5.ArrayList插入和查詢數(shù)據(jù)原理

? ? ? ? 接下來(lái)我們透過(guò)ArrayList的具體方法操作,看ArrayList是如何進(jìn)行元素的收集的凿叠,因?yàn)锳rrayList底層本質(zhì)是數(shù)組,且實(shí)現(xiàn)了List接口,使用中可以方便調(diào)用List接口定義的add()功能向ArrayList添加內(nèi)容盒件。


ArrayList添加內(nèi)容

? ? ? ? 可以發(fā)現(xiàn)蹬碧,向ArrayList中插入數(shù)據(jù),如果插入的數(shù)據(jù)位于數(shù)組末尾性能非吵吹螅快恩沽,但是向數(shù)組中間插入就需要將插入位置后面的所有數(shù)據(jù)順序后移,非常消耗性能翔始,同理remove 集合ArrayList中的一個(gè)數(shù)據(jù)罗心,也會(huì)導(dǎo)致冗長(zhǎng)的移位操作,性能消耗得不償失城瞎。所以對(duì)于ArrayList最好不要輕易改變帶索引的數(shù)據(jù)渤闷。

? ? ? ? 知道了數(shù)據(jù)的增刪之后,再來(lái)看看ArrayList進(jìn)行數(shù)據(jù)訪問(wèn)是如何實(shí)現(xiàn)的脖镀?下圖是ArrayList定義的獲取值的方法


ArrayList通過(guò)索引獲取對(duì)象

? ? ? ? 代碼中ArrayList需要傳入索引地址飒箭,方法定義通過(guò)索引隨機(jī)訪問(wèn)數(shù)組索引位置的數(shù)據(jù)。它的訪問(wèn)時(shí)間復(fù)雜度O(1)蜒灰,性能非常的快弦蹂。所以ArrayList適合一次加載多次訪問(wèn)的數(shù)據(jù)非常的適合。既然ArrayList在查詢方面性能如此適合强窖,那么可以直接使用ArrayList做多線程公共數(shù)據(jù)的查詢服務(wù)嗎凸椿?答案是不可以的。

6.ArrayList安全性淺析和應(yīng)對(duì)方法

? ? ? ? 因?yàn)锳rrayList是線程不安全的翅溺,ArrayList的操作并非是原子性的脑漫,通讀ArrayList代碼并沒(méi)有實(shí)現(xiàn)線程同步機(jī)制的加鎖約束。ArrayList添加一個(gè)元素的時(shí)候未巫,需要兩個(gè)步驟窿撬,第一步在Items[Size]的位置存放此元素,第二步增大Size的值叙凡,在單線程運(yùn)行的情況劈伴,這兩個(gè)步驟是順序執(zhí)行的,互相不會(huì)影響握爷。但是如果有兩個(gè)線程去操作呢跛璧?

? ? ? ? 線程A在0的位置賦了一個(gè)值,然后停下來(lái)新啼,B線程ArrayList 0的位置又賦了一個(gè)值追城,其實(shí)是重復(fù)在一個(gè)位置賦值,然后回到A線程燥撞,執(zhí)行Size增加座柱,也就是ArrayList的大小增加了迷帜,原來(lái)Size是1,現(xiàn)在變成2色洞,然后停下來(lái)繼續(xù)執(zhí)行線程B戏锹,又增加了一個(gè)空間位置,size大小就變成了3火诸,結(jié)果就是0的位置有值锦针,1和2的索引位置都沒(méi)有值實(shí)際大小是3,跟想要的結(jié)果0和1賦不同的值置蜀,結(jié)果不對(duì)奈搜。那么如何來(lái)解決這個(gè)問(wèn)題呢?

? ? ? ? 在JVM的ArrayList設(shè)計(jì)的時(shí)候給出了兩個(gè)方法可以讓程序員既能利用ArrayList的隨機(jī)訪問(wèn)的高效性能盯荤,又能避免并發(fā)訪問(wèn)線程安全問(wèn)題馋吗。

方法一、繼承Arraylist廷雅,然后重寫(xiě)或按需求編寫(xiě)自己的方法耗美,這些方法要寫(xiě)成synchronized,在這些synchronized的方法中調(diào)用ArrayList的方法航缀。

方法二商架、使用Collections.synchronizedList的接口,如下使用:

List list =Collections.synchronizedList(new ArrayList());

方法一可以實(shí)現(xiàn)芥玉,但是對(duì)于程序開(kāi)發(fā)者來(lái)說(shuō)加大了工作難度蛇摸,列在這里供參考。為了使用方便推薦直接使用方法二灿巧,因?yàn)镃ollections.synchronizedList已經(jīng)實(shí)現(xiàn)了ArrayList的線程安全赶袄,所以不用重復(fù)造輪子了。

? ? ? ? 通過(guò)今天的分享希望大家對(duì)ArrayList有深入的了解抠藕。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末饿肺,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子盾似,更是在濱河造成了極大的恐慌敬辣,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件零院,死亡現(xiàn)場(chǎng)離奇詭異溉跃,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)告抄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)撰茎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人打洼,你說(shuō)我怎么就攤上這事龄糊∧娲猓” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵绎签,是天一觀的道長(zhǎng)枯饿。 經(jīng)常有香客問(wèn)我,道長(zhǎng)诡必,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任搔扁,我火速辦了婚禮爸舒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘稿蹲。我一直安慰自己扭勉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布苛聘。 她就那樣靜靜地躺著涂炎,像睡著了一般。 火紅的嫁衣襯著肌膚如雪设哗。 梳的紋絲不亂的頭發(fā)上唱捣,一...
    開(kāi)封第一講書(shū)人閱讀 52,268評(píng)論 1 309
  • 那天,我揣著相機(jī)與錄音网梢,去河邊找鬼震缭。 笑死,一個(gè)胖子當(dāng)著我的面吹牛战虏,可吹牛的內(nèi)容都是我干的拣宰。 我是一名探鬼主播,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼烦感,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼巡社!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起手趣,我...
    開(kāi)封第一講書(shū)人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤晌该,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后回懦,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體气笙,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年怯晕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了潜圃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡舟茶,死狀恐怖谭期,靈堂內(nèi)的尸體忽然破棺而出堵第,到底是詐尸還是另有隱情,我是刑警寧澤隧出,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布踏志,位于F島的核電站,受9級(jí)特大地震影響胀瞪,放射性物質(zhì)發(fā)生泄漏针余。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一凄诞、第九天 我趴在偏房一處隱蔽的房頂上張望圆雁。 院中可真熱鬧,春花似錦帆谍、人聲如沸伪朽。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)烈涮。三九已至,卻和暖如春窖剑,著一層夾襖步出監(jiān)牢的瞬間坚洽,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工苛吱, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留酪术,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓翠储,卻偏偏與公主長(zhǎng)得像绘雁,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子援所,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 在一個(gè)方法內(nèi)部定義的變量都存儲(chǔ)在棧中庐舟,當(dāng)這個(gè)函數(shù)運(yùn)行結(jié)束后,其對(duì)應(yīng)的棧就會(huì)被回收住拭,此時(shí)挪略,在其方法體中定義的變量將不...
    Y了個(gè)J閱讀 4,420評(píng)論 1 14
  • Java繼承關(guān)系初始化順序 父類的靜態(tài)變量-->父類的靜態(tài)代碼塊-->子類的靜態(tài)變量-->子類的靜態(tài)代碼快-->父...
    第六象限閱讀 2,159評(píng)論 0 9
  • 誤會(huì) 早年在美國(guó)阿拉斯加地方,有一對(duì)年輕人結(jié)婚滔岳,婚后生育杠娱,他的太太因難產(chǎn)而死,遺下一孩子谱煤。 他忙生活摊求,又忙于看家,...
    威樂(lè)河灣閱讀 465評(píng)論 0 1
  • 今天我要說(shuō)的是刘离,這么多年我把自己排除在外室叉,以為不走進(jìn)睹栖,就不會(huì)傷害!但是發(fā)現(xiàn)茧痕,現(xiàn)實(shí)的生活也好野来,人也罷,并不會(huì)因?yàn)槟愕?..
    翻滾吧逆流而上的魚(yú)閱讀 279評(píng)論 0 0