談?wù)凙rrayList、Vector和LinkedList 的存儲性能及特性
? 又有一位工作2年的小伙伴面試的時候,被問到一個集合相關(guān)的問題。說請你談?wù)凙rrayList、Vector和LinkedList 的存儲性能及特性。
今天呢,我給大家分享一下我對這個問題的理解。
?1、存儲性能及特性
關(guān)于ArrayList、Vector和LinkedList 的存性能理及特性,我從以下3個方面來分析:
(1)首先,ArrayList 和 Vector 的底層都是采用數(shù)組的來存儲數(shù)據(jù),而且都是根據(jù)索引來取數(shù)據(jù),這樣設(shè)計(jì)使得獲取數(shù)據(jù)快而插入數(shù)據(jù)慢。另外,每次擴(kuò)容都要移動數(shù)組中的元素,存儲數(shù)據(jù)量較大的時候會影響讀寫性能。
(2)其次,由于Vector 中的方法都使用了 synchronized 修飾,因此 ,Vector 中對數(shù)據(jù)操作都是線程安全的,但性能上比ArrayList 差。
(3)然后,LinkedList 的底層是采用雙向鏈表來存儲數(shù)據(jù)的,也就是說將內(nèi)存中零散的內(nèi)存單元通過附加的引用關(guān)聯(lián)起來,形成一個可以按序號索引的線性結(jié)構(gòu),這種鏈?zhǔn)酱鎯Ψ绞脚c數(shù)組的連續(xù)存儲方式相比,內(nèi)存的利用率更高。LinkedList獲取數(shù)據(jù)需要根據(jù)索引序號,向前或者向后遍歷,但是插入數(shù)據(jù)時只需要記錄本項(xiàng)的前后項(xiàng)即可,所以,LinkedList插入數(shù)據(jù)的速度更快。
(4)最后,再補(bǔ)充一點(diǎn),Vector是Java 早期的版本中提供的容器, 屬于遺留容器,官方已經(jīng)不再推薦使用。但是由于 ArrayList 和 LinkedListed 都是非線程安全的,在多線程環(huán)境下,可以使用工具類Collections 的 synchronizedList() 方法,將容器轉(zhuǎn)換成線程安全的容器再使用。這其實(shí)也是裝飾器模式的一種應(yīng)用。
2、關(guān)于遺留容器
關(guān)于Java中的遺留容器,我最后再補(bǔ)充一下。除Vector之外,還有Hashtable、Dictionary、BitSet、Stack、Properties都是遺留容器,這些容器中,Properties 類存在比較嚴(yán)重的設(shè)計(jì)缺陷。來看這段源碼:
/* Since : JDK1.0 See Also : native2ascii tool for Solaris, native2ascii tool for Windows Author : Arthur van Hoff, Michael McCloskey, Xueming Shen */ public class Properties extends Hashtable<Object,Object> { }
Properties是一個鍵和值都是字符串的特殊的鍵值對映射,在設(shè)計(jì)上應(yīng)該是關(guān)聯(lián)一個Hashtable,并將它的兩個泛型參數(shù)設(shè)置為 String 類型,但是 Java API 中的Properties是直接繼承了 Hashtable,這很明顯是對繼承的濫用。主要體現(xiàn)在以下兩個方面:
(1)首先,根據(jù)合成復(fù)用原則,這里Properties 和Hashtable的代碼復(fù)用關(guān)系應(yīng)該是 Has-A 關(guān)系,而不是 Is-A 關(guān)系。
(2)另一方面,這兩個容器都屬于工具類,繼承工具類本身就是一個錯誤的做法,使用工具類最好的方式是 Has-A 關(guān)系(關(guān)聯(lián))或Use-A 關(guān)系(依賴)。
既然都講到這里了,最后再擴(kuò)展一下Stack 類在設(shè)計(jì)上也存在Properties同樣的缺陷。來看這樣一段源碼:
/* Since : JDK1.0 Author : Jonathan Payne */ public class Stack<E> extends Vector<E> { }
在JDK的util包中,我們發(fā)現(xiàn)Stack類也是繼承了 Vector,這個設(shè)計(jì)也是不太合理的。
好了,以上就是我對ArrayList、Vector和LinkedList的理解。