摘要:在反射方面來說,從運(yùn)行時(shí)返回一個(gè)的實(shí)例時(shí)不需要經(jīng)過強(qiáng)制轉(zhuǎn)換然后則需要經(jīng)過轉(zhuǎn)換才能得到。如果對(duì)數(shù)據(jù)的數(shù)量大小已知,操作也非常簡單,也不需要中的大部分方法,也是可以直接使用數(shù)組的。
我在想每個(gè)人在面試的時(shí)候都會(huì)被問到集合相關(guān)的問題,有好大一部分人在回答的時(shí)候并沒有那么多的邏輯性,通常都是想到哪里說到哪里,這篇文章大概的捋一捋關(guān)于集合的相關(guān)問題。
在每種編程語言中,都會(huì)有循環(huán)、數(shù)組、流程控制語句,數(shù)組是一種線性表數(shù)據(jù)結(jié)構(gòu),內(nèi)存空間是連續(xù)的,保存的數(shù)據(jù)類型也是一致的。
正是因?yàn)檫@兩點(diǎn),數(shù)組的隨機(jī)訪問才會(huì)非常的高效,這同時(shí)也是一把雙刃劍,使得數(shù)組的其他操作效率變得很低,比如說,增加,刪除,為了保持?jǐn)?shù)組里面數(shù)據(jù)的連續(xù)性,就會(huì)做大量的消耗性能的數(shù)據(jù)遷移操作。
針對(duì)數(shù)組這種類型,java中有容器類,比如ArrayList,ArrayList是對(duì)數(shù)組的包裝,在底層就是數(shù)組實(shí)現(xiàn)的,因?yàn)閿?shù)組在定義的時(shí)候必須是指定的長度,定義之后就無法再增加長度了,就是說不可能在原來的數(shù)組上接上一段,所以ArrayList就解決了這個(gè)問題,當(dāng)超過數(shù)組容量的時(shí)候,ArrayList會(huì)進(jìn)行擴(kuò)容,擴(kuò)容之后的容量是之前的1.5倍,然后再把之前數(shù)組中的數(shù)據(jù)復(fù)制過來。
接下來,我們看下ArrayList的源碼:
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
源碼中數(shù)組最大的容量是Integer.MAX_VALUE -8,為什么要減去8 呢,這個(gè)是上面的定義上面的注釋:
/** * The maximum size of array to allocate. * Some VMs reserve some header words in an array. * Attempts to allocate larger arrays may result in * OutOfMemoryError: Requested array size exceeds VM limit */
首先是一些VM在數(shù)組中保存的頭信息;嘗試著去分配更大的數(shù)組可能會(huì)導(dǎo)致OutOfMemoryError,請(qǐng)求的數(shù)組大小超過了VM的限制。
在看這句代碼的時(shí)候,腦中有沒有出現(xiàn)兩個(gè)大大的問號(hào)??
首先,有沒有想到為什么這個(gè)數(shù)組屬性需要用 transient修飾?
(想知道這個(gè)關(guān)鍵字是干什么的,可以看下我之前的一篇文章:面試問你java中的序列化怎么答?)
transient Object[] elementData; // non-private to simplify nested class access
大家可以隨便的想一下,如果是面試的時(shí)候,你會(huì)怎么回答?
由于 ArrayList 是基于動(dòng)態(tài)數(shù)組實(shí)現(xiàn)的,所以并不是所有的空間都被使用。因此使用了 transient 修飾,可以防止被自動(dòng)序列化。
因此 ArrayList 自定義了序列化與反序列化,具體可以看 writeObject 和 readObject 兩個(gè)方法。
需要注意的一點(diǎn)是,當(dāng)對(duì)象中自定義了 writeObject 和 readObject 方法時(shí),JVM 會(huì)調(diào)用這兩個(gè)自定義方法來實(shí)現(xiàn)序列化與反序列化。
第二個(gè)問題:這個(gè)屬性的類型為什么是Object而不是泛型?
這里和大家說下:
java中泛型運(yùn)用的目的就是對(duì)象的重用,就是同一個(gè)方法,可以支持多種對(duì)象類型,Object和泛型在編寫的時(shí)候其實(shí)沒有太大的區(qū)別,只是JVM中沒有T這個(gè)概念,T只是存在編寫的時(shí)候,進(jìn)入虛擬機(jī)運(yùn)行的時(shí)候,虛擬機(jī)會(huì)對(duì)這種泛型標(biāo)志進(jìn)行擦除,也就是替換T到指定的類型,如果沒有指定類型,就會(huì)用Object替換,同時(shí)Object可以new Object(),就是說可以實(shí)例化,而T則不能實(shí)例化。在反射方面來說,從運(yùn)行時(shí),返回一個(gè)T的實(shí)例時(shí),不需要經(jīng)過強(qiáng)制轉(zhuǎn)換,然后Object則需要經(jīng)過轉(zhuǎn)換才能得到。
當(dāng)我們?cè)噲D向ArrayList中添加一個(gè)元素的時(shí)候,java會(huì)自動(dòng)檢查,以確保集合中確實(shí)還有容量來添加新元素,如果沒有,就會(huì)自動(dòng)擴(kuò)容,下面是核心代碼,我已經(jīng)在代碼里加了注釋,幫助大家能夠更好的理解:
private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); }
上面這段代碼中有個(gè) 變量 modCount++,看到這里的時(shí)候確實(shí)有些疑惑,我找了下,這個(gè)變量是在AbstractList中定義的protected修飾的全局變量,這個(gè)變量是記錄了結(jié)構(gòu)性改變的次數(shù),結(jié)構(gòu)性改變就是說修改列表大小的操作。
ArrayList是一個(gè)線程不安全的類,這個(gè)變量就是用來保證在多線程環(huán)境下使用迭代器的時(shí)候,同時(shí)又對(duì)集合進(jìn)行了修改,同一時(shí)刻只能有一個(gè)線程修改集合,如果多于一個(gè),就會(huì)拋出ConcurrentModficationException。
private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; //核心的擴(kuò)容代碼:擴(kuò)容之后的容量, int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) //擴(kuò)容之后的容量與本次操作需要的容量對(duì)比,取更大的 newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) //在與數(shù)組的最大容量對(duì)比,如果比最大的容量大,進(jìn)入下一個(gè)方法 newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: //接下來,是把原數(shù)組d 數(shù)據(jù)復(fù)制到新的數(shù)組里 elementData = Arrays.copyOf(elementData, newCapacity); } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); //當(dāng) Integer-8 依然無法滿足需求,就會(huì)取Integer的最大值 return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
接下來我們看下,向指定位置添加元素是什么樣的:
public void add(int index, E element) { rangeCheckForAdd(index); //擴(kuò)容校驗(yàn) ensureCapacityInternal(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; }
可以看到,當(dāng)一個(gè)集合足夠大的時(shí)候,add操作向數(shù)組的尾部添加元素效率還是非常高的,但是當(dāng)向指定的位置添加元素的時(shí)候,也是需要大量的移動(dòng)復(fù)制操作:System.arraycopy()。
到這里,ArrayList最大的優(yōu)勢是什么呢?我們?cè)谄綍r(shí)的開發(fā)中涉及到容器的時(shí)候?yàn)槭裁磿?huì)選擇List家族的成員,而不直接選擇數(shù)組呢?大家回想一下自己之前敲代碼的經(jīng)歷,答案也就出來了:
ArrayList封裝了大部分?jǐn)?shù)組的操作方法,比如插入、刪除、搬移數(shù)據(jù)等等,都在集合內(nèi)部幫你做好了,還有就是支持動(dòng)態(tài)擴(kuò)容,這點(diǎn)是數(shù)組不能比擬的。
這里需要注意一點(diǎn),當(dāng)我們?cè)陂_始定義集合的時(shí)候,如果知道我們需要多大的集合,就應(yīng)該在一開始就指定集合的大小,因?yàn)樵诩系膬?nèi)部來進(jìn)行數(shù)據(jù)的搬移,復(fù)制也是非常耗時(shí)的。
那么數(shù)組在什么時(shí)候會(huì)用到呢?
1、java ArrayList無法存儲(chǔ)基本類型,int,long,如果保存的話,就需要封裝為Integer、Long,而自動(dòng)的拆裝箱,也有性能的消耗,所以總結(jié)下這點(diǎn)就是說如果要保存基本類型,同時(shí)還特別關(guān)注性能,就可以使用數(shù)組。
2、如果對(duì)數(shù)據(jù)的數(shù)量大小已知,操作也非常簡單,也不需要ArrayList中的大部分方法,也是可以直接使用數(shù)組的。
如果對(duì)本文有任何異議,可以加我好友(有沒有問題都?xì)g迎大家加我好友),也可以在下面留言區(qū)留言,我會(huì)及時(shí)修改。希望這篇文章能幫助大家在面試路上乘風(fēng)破浪。
這樣的分享我會(huì)一直持續(xù),你的關(guān)注、轉(zhuǎn)發(fā)和好看是對(duì)我最大的支持,感謝。關(guān)注我,我們一起成長。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/74151.html
摘要:前言秋招宣告結(jié)束,面試了接近家公司,有幸拿到,感謝這段時(shí)間一起找工作面試的朋友和陪伴我的人。一定要提前準(zhǔn)備好,不然面試官叫你說遇到的難點(diǎn),或者直接問問題時(shí)可能會(huì)懵逼。 前言 秋招宣告結(jié)束,面試了接近20家公司,有幸拿到offer,感謝這段時(shí)間一起找工作面試的朋友和陪伴我的人。這是一段難忘的經(jīng)歷,相信不亞于當(dāng)年的高考吧,也許現(xiàn)在想起來高考不算什么,也許只有經(jīng)歷過秋招的人才懂得找工作的艱辛...
摘要:前言秋招宣告結(jié)束,面試了接近家公司,有幸拿到,感謝這段時(shí)間一起找工作面試的朋友和陪伴我的人。一定要提前準(zhǔn)備好,不然面試官叫你說遇到的難點(diǎn),或者直接問問題時(shí)可能會(huì)懵逼。 前言 秋招宣告結(jié)束,面試了接近20家公司,有幸拿到offer,感謝這段時(shí)間一起找工作面試的朋友和陪伴我的人。這是一段難忘的經(jīng)歷,相信不亞于當(dāng)年的高考吧,也許現(xiàn)在想起來高考不算什么,也許只有經(jīng)歷過秋招的人才懂得找工作的艱辛...
摘要:背景在開發(fā)好頁面后,如何讓頁面更快更好的運(yùn)行,是區(qū)分一個(gè)程序猿技術(shù)水平和視野的一個(gè)重要指標(biāo)。在對(duì)這些環(huán)節(jié)進(jìn)行優(yōu)化之前,我們需要知道如何監(jiān)控這些環(huán)節(jié)花費(fèi)了多少時(shí)間。為了優(yōu)化鏈接的環(huán)節(jié),前端這里還需要對(duì)資源使用,雪碧圖,代碼合并等手段。 背景 在開發(fā)好頁面后,如何讓頁面更快更好的運(yùn)行,是區(qū)分一個(gè)程序猿技術(shù)水平和視野的一個(gè)重要指標(biāo)。所以面試時(shí),面試官總會(huì)問你一個(gè)問題,如何進(jìn)行性能優(yōu)化呢? 如...
摘要:正因?yàn)槿绱?,現(xiàn)在很多簡歷上的項(xiàng)目經(jīng)歷的質(zhì)量都是參差不齊,同時(shí)有的項(xiàng)目經(jīng)歷又非常相似,面試官一眼就能知道你的項(xiàng)目到底是真是假。雖然以上三點(diǎn)原則不能包治百病,但是對(duì)很多同學(xué)來說應(yīng)該是蠻有益處的。閱讀本文大概需要 5 分鐘。作者:黃小斜showImg(https://user-gold-cdn.xitu.io/2019/3/30/169cdb4bd2cac24c);?作為一個(gè)程序員,想必大家曾經(jīng)都...
摘要:正確做法是給加索引,還有聯(lián)合索引,并不能避免全表掃描。 前言:有收獲的話請(qǐng)加顆小星星,沒有收獲的話可以 反對(duì) 沒有幫助 舉報(bào)三連 有心的同學(xué)應(yīng)該會(huì)看到我這個(gè)noteBook下面的其它知識(shí),希望對(duì)你們有些許幫助。 本文地址 時(shí)間點(diǎn):2017-11 一個(gè)16年畢業(yè)生所經(jīng)歷的php面試 一、什么是面試 二、面試準(zhǔn)備 1. 問:什么時(shí)候開始準(zhǔn)備? 2. 問:怎么準(zhǔn)備? 三、面試...
閱讀 3276·2021-09-30 09:48
閱讀 3582·2021-09-22 16:00
閱讀 1125·2019-08-30 13:08
閱讀 3187·2019-08-30 10:53
閱讀 2473·2019-08-29 18:33
閱讀 1642·2019-08-29 12:47
閱讀 950·2019-08-29 12:16
閱讀 1992·2019-08-26 12:02