為什么這兩個放在一起說懂拾,而沒有分開寫呢捅儒?
誠然液样,集合或者數(shù)組二者隨便其一,都不是一篇博客能寫完的巧还。但是在面試中鞭莽,面試官一般不會出很多這方面的面試題,所以我們把數(shù)組和集合放在一起寫一篇博客麸祷。本文只羅列幾個高頻題澎怒,不羅列難題和全面集合或數(shù)組的知識點。如果想知道更多集合或者數(shù)組的知識點阶牍,可以私我向我索取喷面。
話不多說,集合底層其實也是數(shù)組走孽。
1.Java集合框架是什么惧辈?說出一些集合框架的優(yōu)點?
每種編程語言中都有集合磕瓷,最初的Java版本包含幾種集合類:Vector盒齿、Stack、HashTable和Array困食。隨著集合的廣泛使用边翁,Java1.2提出了囊括所有集合接口、實現(xiàn)和算法的集合框架陷舅。在保證線程安全的情況下使用泛型和并發(fā)集合類倒彰,Java已經(jīng)經(jīng)歷了很久。它還包括在Java并發(fā)包中莱睁,阻塞接口以及它們的實現(xiàn)待讳。集合框架的部分優(yōu)點如下:
(1)使用核心集合類降低開發(fā)成本芒澜,而非實現(xiàn)我們自己的集合類。
(2)隨著使用經(jīng)過嚴格測試的集合框架類创淡,代碼質(zhì)量會得到提高痴晦。
(3)通過使用JDK附帶的集合類,可以降低代碼維護成本琳彩。
(4)復用性和可操作性誊酌。
2.集合框架中的泛型有什么優(yōu)點?
Java1.5引入了泛型露乏,所有的集合接口和實現(xiàn)都大量地使用它碧浊。泛型允許我們?yōu)榧咸峁┮粋€可以容納的對象類型,因此瘟仿,如果你添加其它類型的任何元素箱锐,它會在編譯時報錯。這避免了在運行時出現(xiàn)ClassCastException劳较,因為你將會在編譯時得到報錯信息驹止。泛型也使得代碼整潔,我們不需要使用顯式轉(zhuǎn)換和instanceOf操作符观蜗。它也給運行時帶來好處臊恋,因為不會產(chǎn)生類型檢查的字節(jié)碼指令。
3.Iterator是什么墓捻?
Iterator接口提供遍歷任何Collection的接口抖仅。我們可以從一個Collection中使用迭代器方法來獲取迭代器實例。迭代器取代了Java集合框架中的Enumeration毙替。迭代器允許調(diào)用者在迭代過程中移除元素岸售。
4.Iterater和ListIterator之間有什么區(qū)別?
(1)我們可以使用Iterator來遍歷Set和List集合厂画,而ListIterator只能遍歷List。
(2)Iterator只可以向前遍歷拷邢,而LIstIterator可以雙向遍歷袱院。
(3)ListIterator從Iterator接口繼承,然后添加了一些額外的功能瞭稼,比如添加一個元素忽洛、替換一個元素、獲取前面或后面元素的索引位置环肘。
5.在Java中欲虚,HashMap是如何工作的?
HashMap在Map.Entry靜態(tài)內(nèi)部類實現(xiàn)中存儲key-value對悔雹。HashMap使用哈希算法复哆,在put和get方法中欣喧,它使用hashCode()和equals()方法。當我們通過傳遞key-value對調(diào)用put方法的時候梯找,HashMap使用Key
hashCode()和哈希算法來找出存儲key-value對的索引唆阿。Entry存儲在LinkedList中,所以如果存在entry锈锤,它使用equals()方法來檢查傳遞的key是否已經(jīng)存在驯鳖,如果存在,它會覆蓋value久免,如果不存在浅辙,它會創(chuàng)建一個新的entry然后保存。當我們通過傳遞key調(diào)用get方法時阎姥,它再次使用hashCode()來找到數(shù)組中的索引记舆,然后使用equals()方法找出正確的Entry,然后返回它的值丁寄。下面的圖片解釋了詳細內(nèi)容氨淌。
其它關(guān)于HashMap比較重要的問題是容量、負荷系數(shù)和閥值調(diào)整伊磺。HashMap默認的初始容量是32盛正,負荷系數(shù)是0.75。閥值是為負荷系數(shù)乘以容量屑埋,無論何時我們嘗試添加一個entry豪筝,如果map的大小比閥值大的時候,HashMap會對map的內(nèi)容進行重新哈希摘能,且使用更大的容量续崖。容量總是2的冪,所以如果你知道你需要存儲大量的key-value對团搞,比如緩存從數(shù)據(jù)庫里面拉取的數(shù)據(jù)严望,使用正確的容量和負荷系數(shù)對HashMap進行初始化是個不錯的做法
6.hashCode()和equals()方法有何重要性?(這一個問題我在前文中有專門寫一篇博客講述)
HashMap使用Key對象的hashCode()和equals()方法去決定key-value對的索引逻恐。當我們試著從HashMap中獲取值的時候像吻,這些方法也會被用到。如果這些方法沒有被正確地實現(xiàn)复隆,在這種情況下拨匆,兩個不同Key也許會產(chǎn)生相同的hashCode()和equals()輸出,HashMap將會認為它們是相同的挽拂,然后覆蓋它們惭每,而非把它們存儲到不同的地方。同樣的亏栈,所有不允許存儲重復數(shù)據(jù)的集合類都使用hashCode()和equals()去查找重復台腥,所以正確實現(xiàn)它們非常重要宏赘。equals()和hashCode()的實現(xiàn)應該遵循以下規(guī)則:
(1)如果o1.equals(o2),那么o1.hashCode()== o2.hashCode()總是為true的览爵。
(2)如果o1.hashCode() == o2.hashCode()置鼻,并不意味著o1.equals(o2)會為true。
7.HashMap和HashTable有何不同蜓竹?
(1)HashMap允許key和value為null箕母,而HashTable不允許。
(2)HashTable是同步的俱济,而HashMap不是嘶是。所以HashMap適合單線程環(huán)境,HashTable適合多線程環(huán)境蛛碌。
(3)在Java1.4中引入了LinkedHashMap聂喇,HashMap的一個子類,假如你想要遍歷順序蔚携,你很容易從HashMap轉(zhuǎn)向LinkedHashMap希太,但是HashTable不是這樣的,它的順序是不可預知的酝蜒。
(4)HashMap提供對key的Set進行遍歷誊辉,因此它是fail-fast的,但HashTable提供對key的Enumeration進行遍歷亡脑,它不支持fail-fast堕澄。
(5)HashTable被認為是個遺留的類,如果你尋求在迭代的時候修改Map霉咨,你應該使用CocurrentHashMap蛙紫。
8.ArrayList和Vector有何異同點?
ArrayList和Vector在很多時候都很類似途戒。
(1)兩者都是基于索引的坑傅,內(nèi)部由一個數(shù)組支持。
(2)兩者維護插入的順序喷斋,我們可以根據(jù)插入順序來獲取元素裁蚁。
(3)ArrayList和Vector的迭代器實現(xiàn)都是fail-fast的。
(4)ArrayList和Vector兩者允許null值继准,也可以使用索引值對元素進行隨機訪問。
以下是ArrayList和Vector的不同點矮男。
(1)Vector是同步的移必,而ArrayList不是。然而毡鉴,如果你尋求在迭代的時候?qū)α斜磉M行改變崔泵,你應該使用CopyOnWriteArrayList秒赤。
(2)ArrayList比Vector快,它因為有同步憎瘸,不會過載入篮。
(3)ArrayList更加通用,因為我們可以使用Collections工具類輕易地獲取同步列表和只讀列表幌甘。
9.Array和ArrayList有何區(qū)別潮售?什么時候更適合用Array?
Array可以容納基本類型和對象锅风,而ArrayList只能容納對象酥诽。
Array是指定大小的,而ArrayList大小是固定的皱埠。
Array沒有提供ArrayList那么多功能肮帐,比如addAll、removeAll和iterator等边器。盡管ArrayList明顯是更好的選擇训枢,但也有些時候Array比較好用。
(1)如果列表的大小已經(jīng)指定忘巧,大部分情況下是存儲和遍歷它們恒界。
(2)對于遍歷基本數(shù)據(jù)類型,盡管Collections使用自動裝箱來減輕編碼任務袋坑,在指定大小的基本類型的列表上工作也會變得很慢仗处。
(3)如果你要使用多維數(shù)組,使用[][]比List<List<>>更容易
10.當一個集合被作為參數(shù)傳遞給一個函數(shù)時枣宫,如何才可以確保函數(shù)不能修改它婆誓?
在作為參數(shù)傳遞之前,我們可以使用Collections.unmodifiableCollection(Collection c)方法創(chuàng)建一個只讀集合也颤,這將確保改變集合的任何操作都會拋出UnsupportedOperationException洋幻。
11.說一下鏈表跟數(shù)組的區(qū)別
鏈表:用一組任意儲存單元存放線性表的數(shù)據(jù)元素,并且通過指針鏈相接結(jié)點的序列稱為鏈表翅娶。是一種常見的數(shù)據(jù)組織形式文留,它采用了動態(tài)分配內(nèi)存的形式實現(xiàn)。需要時可以用new分配內(nèi)存空間竭沫,不需要時用delete將已分配的空間釋放燥翅,不會造成內(nèi)存空間的浪費。不靠數(shù)組實現(xiàn)蜕提,沒有下標森书。數(shù)組必須事先定義固定的長度,不能適應數(shù)據(jù)動態(tài)增減的情況。當數(shù)據(jù)增加時凛膏,可能超出原先定義的元素個數(shù)杨名;當數(shù)據(jù)減少時,造成數(shù)據(jù)浪費猖毫。在使用的時候還要數(shù)組初始化台谍,注意數(shù)組的下標越界。
12.ArrayList集合加入1萬條數(shù)據(jù)吁断,應該怎么提高效率
因為ArrayList的底層是數(shù)組實現(xiàn),并且數(shù)組的默認值是10,如果插入10000條要不斷的擴容,耗費時間,所以我們調(diào)用ArrayList的指定容量的構(gòu)造器方法ArrayList(int size) 就可以實現(xiàn)不擴容,就提高了性能
最后給大家出一個高頻面試題:隊列和棧是什么趁蕊,列出它們的區(qū)別?各位自己去查吧胯府,這個問題我就不做解答了介衔。
給大家一個提示:棧和隊列兩者都被用來預存儲數(shù)據(jù)。java.util.Queue是一個接口骂因,它的實現(xiàn)類在Java并發(fā)包中炎咖。隊列允許先進先出(FIFO)檢索元素,但并非總是這樣寒波。Deque接口允許從兩端檢索元素乘盼。
棧與隊列很相似,但它允許對元素進行后進先出(LIFO)進行檢索俄烁。
Stack是一個擴展自Vector的類绸栅,而Queue是一個接口。
隊列的兩個基本操作:一個是插入一個數(shù)據(jù)項页屠,即把一個數(shù)據(jù)項放入隊尾另一個是移除一個數(shù)據(jù)項粹胯,即移除隊頭的數(shù)據(jù)項.
最后給大家來一個開心一笑