ArrayList哺呜、LinkedList、Vector的區(qū)別

Arraylist和Vector是采用數(shù)組方式存儲數(shù)據(jù)箕戳,此數(shù)組元素數(shù)大于實際存儲的數(shù)據(jù)以便增加插入元素某残,都允許直接序號索引元素国撵,但是插入數(shù)據(jù)要涉及到數(shù)組元素移動等內(nèi)存操作,所以插入數(shù)據(jù)慢玻墅,查找有下標(biāo)介牙,所以查詢數(shù)據(jù)快,Vector由于使用了synchronized方法-線程安全澳厢,所以性能上比ArrayList要差环础,LinkedList使用雙向鏈表實現(xiàn)存儲,按序號索引數(shù)據(jù)需要進(jìn)行向前或向后遍歷赏酥,但是插入數(shù)據(jù)時只需要記錄本項前后項即可喳整,插入數(shù)據(jù)較快谆构。

線性表裸扶,鏈表,哈希表是常用的數(shù)據(jù)結(jié)構(gòu)搬素,在進(jìn)行java開發(fā)時呵晨,JDK已經(jīng)為我們提供了一系列相應(yīng)的類實現(xiàn)基本的數(shù)據(jù)結(jié)構(gòu),這些結(jié)構(gòu)均在java.util包中熬尺,

collection

├List

│├LinkedList

│├ArrayList

│└Vector

│ └Stack

└Set

Map

├Hashtable

├HashMap

└WeakHashMap

Collection接口

Collection是最基本的集合接口摸屠,一個Collection代表一組Object,即Collection的元素(elements)粱哼,一些Collection允許相同的元素而另一些不行季二。一些能排序而另一些不行。Java?SDK不提供直接繼承自Collection的類揭措,Java?SDK提供的類都是繼承自Collection的“子接口”如List和Set胯舷。

所有實現(xiàn)Collection接口的類都必須提供兩個標(biāo)準(zhǔn)的構(gòu)造函數(shù):無參數(shù)的構(gòu)造函數(shù)用于創(chuàng)建一個空的Collection,有一個Collection參數(shù)的構(gòu)造函數(shù)用于創(chuàng)建一個新的Collection绊含,這個新的Collection與傳入的Collection有相同的元素桑嘶。后一個構(gòu)造函數(shù)允許用戶復(fù)制一個Collection。

如何遍歷Collection中的每一個元素躬充?不論Collection的實際類型如何逃顶,它都支持一個iterator()的方法,該方法返回一個迭代子充甚,使用該迭代子即可逐一訪問Collection中每一個元素以政。典型的用法如下:

Iterator?it?=?collection.iterator();?//?獲得一個迭代子

while(it.hasNext())?{

Object?obj?=?it.next();?//?得到下一個元素

}

由Collection接口派生的兩個接口是List和Set。

List接口

List是有序的Collection伴找,使用此接口能夠精確的控制每個元素插入的位置盈蛮。用戶能夠使用索引(元素在List中的位置,類似于數(shù)組下標(biāo))來訪問List中的元素疆瑰,這類似于Java的數(shù)組眉反。

和下面要提到的Set不同昙啄,List允許有相同的元素。

除了具有Collection接口必備的iterator()方法外寸五,List還提供一個listIterator()方法梳凛,返回一個ListIterator接口,和標(biāo)準(zhǔn)的Iterator接口相比梳杏,ListIterator多了一些add()之類的方法韧拒,允許添加,刪除十性,設(shè)定元素叛溢,還能向前或向后遍歷。

實現(xiàn)List接口的常用類有LinkedList劲适,ArrayList楷掉,Vector和Stack。

ArrayList類

ArrayList實現(xiàn)了可變大小的數(shù)組霞势。它允許所有元素烹植,包括null。ArrayList沒有同步愕贡。

size草雕,isEmpty,get固以,set方法運(yùn)行時間為常數(shù)墩虹。但是add方法開銷為分?jǐn)偟某?shù),添加n個元素需要O(n)的時間憨琳。其他的方法運(yùn)行時間為線性诫钓。

每個ArrayList實例都有一個容量(Capacity),即用于存儲元素的數(shù)組的大小栽渴。這個容量可隨著不斷添加新元素而自動增加尖坤,但是增長算法并沒有定義。當(dāng)需要插入大量元素時闲擦,在插入前可以調(diào)用ensureCapacity方法來增加ArrayList的容量以提高插入效率慢味。

和LinkedList一樣,ArrayList也是非同步的(unsynchronized)墅冷。

Vector類

Vector非常類似ArrayList纯路,但是Vector是同步的。由Vector創(chuàng)建的Iterator寞忿,雖然和ArrayList創(chuàng)建的Iterator是同一接口驰唬,但是,因為Vector是同步的,當(dāng)一個Iterator被創(chuàng)建而且正在被使用叫编,另一個線程改變了Vector的狀態(tài)(例如辖佣,添加或刪除了一些元素),這時調(diào)用Iterator的方法時將拋出ConcurrentModificationException搓逾,因此必須捕獲該異常卷谈。

Stack?類

Stack繼承自Vector,實現(xiàn)一個后進(jìn)先出的堆棧霞篡。Stack提供5個額外的方法使得Vector得以被當(dāng)作堆棧使用世蔗。基本的push和pop方法朗兵,還有peek方法得到棧頂?shù)脑匚哿埽琫mpty方法測試堆棧是否為空,search方法檢測一個元素在堆棧中的位置余掖。Stack剛創(chuàng)建后是空棧寸爆。

Map接口

請注意,Map沒有繼承Collection接口浊吏,Map提供key到value的映射而昨。一個Map中不能包含相同的key救氯,每個key只能映射一個value找田。Map接口提供3種集合的視圖,Map的內(nèi)容可以被當(dāng)作一組key集合着憨,一組value集合墩衙,或者一組key-value映射。

Hashtable類

Hashtable繼承Map接口甲抖,實現(xiàn)一個key-value映射的哈希表漆改。任何非空(non-null)的對象都可作為key或者value。

添加數(shù)據(jù)使用put(key,?value)准谚,取出數(shù)據(jù)使用get(key)挫剑,這兩個基本操作的時間開銷為常數(shù)。

Hashtable通過initial?capacity和load?factor兩個參數(shù)調(diào)整性能柱衔。通常缺省的load?factor?0.75較好地實現(xiàn)了時間和空間的均衡樊破。增大load?factor可以節(jié)省空間但相應(yīng)的查找時間將增大,這會影響像get和put這樣的操作唆铐。

使用Hashtable的簡單示例如下哲戚,將1,2艾岂,3放到Hashtable中顺少,他們的key分別是”one”,”two”,”three”:

Hashtablenumbers?=?newHashtable();

numbers.put(“one”,?new?Integer(1));

numbers.put(“two”,?new?Integer(2));

numbers.put(“three”,?new?Integer(3));

要取出一個數(shù)脆炎,比如2梅猿,用相應(yīng)的key:

Integer?n?=?(Integer)numbers.get(“two”);

System.out.println(“two?=?”?+?n);

由于作為key的對象將通過計算其散列函數(shù)來確定與之對應(yīng)的value的位置,因此任何作為key的對象都必須實現(xiàn)hashCode和equals方法秒裕。hashCode和equals方法繼承自根類Object粒没,如果你用自定義的類當(dāng)作key的話,要相當(dāng)小心簇爆,按照散列函數(shù)的定義癞松,如果兩個對象相同,即obj1.equals(obj2)=true入蛆,則它們的hashCode必須相同响蓉,但如果兩個對象不同,則它們的hashCode不一定不同哨毁,如果兩個不同對象的hashCode相同枫甲,這種現(xiàn)象稱為沖突,沖突會導(dǎo)致操作哈希表的時間開銷增大扼褪,所以盡量定義好的hashCode()方法想幻,能加快哈希表的操作。

如果相同的對象有不同的hashCode话浇,對哈希表的操作會出現(xiàn)意想不到的結(jié)果(期待的get方法返回null)脏毯,要避免這種問題,只需要牢記一條:要同時復(fù)寫equals方法和hashCode方法幔崖,而不要只寫其中一個食店。

Hashtable是同步的。

HashMap類

HashMap和Hashtable類似赏寇,不同之處在于HashMap是非同步的吉嫩,并且允許null,即null?value和null?key嗅定。自娩,但是將HashMap視為Collection時(values()方法可返回Collection),其迭代子操作時間開銷和HashMap的容量成比例渠退。因此忙迁,如果迭代操作的性能相當(dāng)重要的話,不要將HashMap的初始化容量設(shè)得過高智什,或者load?factor過低动漾。

WeakHashMap類

WeakHashMap是一種改進(jìn)的HashMap,它對key實行“弱引用”荠锭,如果一個key不再被外部所引用旱眯,那么該key可以被GC回收。

總結(jié)

如果涉及到堆棧,隊列等操作删豺,應(yīng)該考慮用List共虑,對于需要快速插入,刪除元素呀页,應(yīng)該使用LinkedList妈拌,如果需要快速隨機(jī)訪問元素,應(yīng)該使用ArrayList蓬蝶。

如果程序在單線程環(huán)境中尘分,或者訪問僅僅在一個線程中進(jìn)行,考慮非同步的類丸氛,其效率較高培愁,如果多個線程可能同時操作一個類,應(yīng)該使用同步的類缓窜。

要特別注意對哈希表的操作定续,作為key的對象要正確復(fù)寫equals和hashCode方法。

盡量返回接口而非實際的類型禾锤,如返回List而非ArrayList私股,這樣如果以后需要將ArrayList換成LinkedList時,客戶端代碼不用改變恩掷。這就是針對抽象編程倡鲸。

同步性

Vector是同步的。這個類中的一些方法保證了Vector中的對象是線程安全的螃成。而ArrayList則是異步的旦签,因此ArrayList中的對象并不是線程安全的。因為同步的要求會影響執(zhí)行的效率寸宏,所以如果你不需要線程安全的集合那么使用ArrayList是一個很好的選擇,這樣可以避免由于同步帶來的不必要的性能開銷偿曙。

數(shù)據(jù)增長

從內(nèi)部實現(xiàn)機(jī)制來講ArrayList和Vector都是使用數(shù)組(Array)來控制集合中的對象氮凝。當(dāng)你向這兩種類型中增加元素的時候,如果元素的數(shù)目超出了內(nèi)部數(shù)組目前的長度它們都需要擴(kuò)展內(nèi)部數(shù)組的長度望忆,Vector缺省情況下自動增長原來一倍的數(shù)組長度罩阵,ArrayList是原來的50%,所以最后你獲得的這個集合所占的空間總是比你實際需要的要大。所以如果你要在集合中保存大量的數(shù)據(jù)那么使用Vector有一些優(yōu)勢启摄,因為你可以通過設(shè)置集合的初始化大小來避免不必要的資源開銷稿壁。

使用模式

在ArrayList和Vector中,從一個指定的位置(通過索引)查找數(shù)據(jù)或是在集合的末尾增加歉备、移除一個元素所花費(fèi)的時間是一樣的傅是,這個時間我們用O(1)表示。但是,如果在集合的其他位置增加或移除元素那么花費(fèi)的時間會呈線形增長:O(n-i)喧笔,其中n代表集合中元素的個數(shù)帽驯,i代表元素增加或移除元素的索引位置。為什么會這樣呢书闸?以為在進(jìn)行上述操作的時候集合中第i和第i個元素之后的所有元素都要執(zhí)行位移的操作尼变。這一切意味著什么呢?

這意味著浆劲,你只是查找特定位置的元素或只在集合的末端增加嫌术、移除元素,那么使用Vector或ArrayList都可以牌借。如果是其他操作蛉威,你最好選擇其他的集合操作類。比如走哺,LinkList集合類在增加或移除集合中任何位置的元素所花費(fèi)的時間都是一樣的?O(1)蚯嫌,但它在索引一個元素的使用缺比較慢-O(i),其中i是索引的位置.使用ArrayList也很容易,因為你可以簡單的使用索引來代替創(chuàng)建iterator對象的操作丙躏。LinkList也會為每個插入的元素創(chuàng)建對象择示,所有你要明白它也會帶來額外的開銷。

最后晒旅,在《Practical?Java》一書中Peter?Haggar建議使用一個簡單的數(shù)組(Array)來代替Vector或ArrayList栅盲。尤其是對于執(zhí)行效率要求高的程序更應(yīng)如此。因為使用數(shù)組(Array)避免了同步废恋、額外的方法調(diào)用和不必要的重新分配空間的操作谈秫。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市鱼鼓,隨后出現(xiàn)的幾起案子拟烫,更是在濱河造成了極大的恐慌,老刑警劉巖迄本,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件硕淑,死亡現(xiàn)場離奇詭異,居然都是意外死亡嘉赎,警方通過查閱死者的電腦和手機(jī)置媳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來公条,“玉大人拇囊,你說我怎么就攤上這事“谐鳎” “怎么了寥袭?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵路捧,是天一觀的道長。 經(jīng)常有香客問我纠永,道長鬓长,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任尝江,我火速辦了婚禮涉波,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘炭序。我一直安慰自己啤覆,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布惭聂。 她就那樣靜靜地躺著窗声,像睡著了一般。 火紅的嫁衣襯著肌膚如雪辜纲。 梳的紋絲不亂的頭發(fā)上笨觅,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天,我揣著相機(jī)與錄音耕腾,去河邊找鬼见剩。 笑死,一個胖子當(dāng)著我的面吹牛扫俺,可吹牛的內(nèi)容都是我干的苍苞。 我是一名探鬼主播,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼狼纬,長吁一口氣:“原來是場噩夢啊……” “哼羹呵!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起疗琉,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤冈欢,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后没炒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體涛癌,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年送火,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片先匪。...
    茶點(diǎn)故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡种吸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出呀非,到底是詐尸還是另有隱情坚俗,我是刑警寧澤镜盯,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站猖败,受9級特大地震影響速缆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜恩闻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一艺糜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧幢尚,春花似錦破停、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至理茎,卻和暖如春黑界,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背皂林。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工朗鸠, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人式撼。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓童社,卻偏偏與公主長得像,于是被迫代替她去往敵國和親著隆。 傳聞我的和親對象是個殘疾皇子扰楼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評論 2 355

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