電子書(shū)下載地址: http://wiki.jikexueyuan.com/project/java-interview-bible/
1. 下列說(shuō)法正確的是()
A. LinkedList繼承自List
B. AbstractSet繼承自Set
C. HashSet繼承自AbstractSet
D. WeakMap繼承自HashMap
答案:AC
解析:下面是一張下載的 Java 中的集合類(lèi)型的繼承關(guān)系圖描扯,一目了然。
2. ArrayList list = new ArrayList(20);中的 list 擴(kuò)充幾次?
A. 0
B. 1
C. 2
D. 3
答案:A
解析:這里有點(diǎn)迷惑人,大家都知道默認(rèn) ArrayList 的長(zhǎng)度是 10 個(gè)缩挑,所以如果你要往 list 里添加 20 個(gè)元素肯定要擴(kuò)充一次(擴(kuò)充為原來(lái)的 1.5 倍)弹渔,但是這里顯示指明了需要多少空間媒熊,所以就一次性為你分配這么多空間帽哑,也就是不需要擴(kuò)充了缸榄。
3. Java集合類(lèi)框架的基本接口有哪些?
Java 集合類(lèi)提供了一套設(shè)計(jì)良好的支持對(duì)一組對(duì)象進(jìn)行操作的接口和類(lèi)祝拯。Java集合類(lèi)里面最基本的接口有:
Collection:代表一組對(duì)象,每一個(gè)對(duì)象都是它的子元素她肯。
Set:不包含重復(fù)元素的 Collection佳头。
List:有順序的 collection,并且可以包含重復(fù)元素晴氨。
Map:可以把鍵(key)映射到值(value)的對(duì)象康嘉,鍵不能重復(fù)。
4. 為什么集合類(lèi)沒(méi)有實(shí)現(xiàn) Cloneable 和 Serializable 接口籽前?
集合類(lèi)接口指定了一組叫做元素的對(duì)象亭珍。集合類(lèi)接口的每一種具體的實(shí)現(xiàn)類(lèi)都可以選擇以它自己的方式對(duì)元素進(jìn)行保存和排序敷钾。有的集合類(lèi)允許重復(fù)的鍵,有些不允許肄梨。
5. 什么是迭代器(Iterator)阻荒?
Iterator 接口提供了很多對(duì)集合元素進(jìn)行迭代的方法。每一個(gè)集合類(lèi)都包含了可以返回迭代器實(shí)例的
迭代方法众羡。迭代器可以在迭代的過(guò)程中刪除底層集合的元素侨赡。
克隆(cloning)或者是序列化(serialization)的語(yǔ)義和含義是跟具體的實(shí)現(xiàn)相關(guān)的。因此粱侣,應(yīng)該由集合類(lèi)的具體實(shí)現(xiàn)來(lái)決定如何被克隆或者是序列化羊壹。
6. Iterator和ListIterator的區(qū)別是什么?
下面列出了他們的區(qū)別:
Iterator 可用來(lái)遍歷 Set 和 List 集合齐婴,但是 ListIterator 只能用來(lái)遍歷 List 油猫。
Iterator 對(duì)集合只能是前向遍歷,ListIterator 既可以前向也可以后向柠偶。
ListIterator 實(shí)現(xiàn)了 Iterator 接口情妖,并包含其他的功能,比如:增加元素嚣州,替換元素鲫售,獲取前一個(gè)和后一個(gè)元素的索引,等等该肴。
7. 快速失敗(fail-fast)和安全失敗(fail-safe)的區(qū)別是什么情竹?
Iterator 的安全失敗是基于對(duì)底層集合做拷貝,因此匀哄,它不受源集合上修改的影響秦效。java.util 包下面的所有的集合類(lèi)都是快速失敗的,而 java.util.concurrent 包下面的所有的類(lèi)都是安全失敗的涎嚼≮逯荩快速失敗的迭代器會(huì)拋出 ConcurrentModificationException 異常,而安全失敗的迭代器永遠(yuǎn)不會(huì)拋出這樣的異常法梯。
8. Java 中的 HashMap 的工作原理是什么苔货?
Java 中的 HashMap 是以鍵值對(duì)(key-value)的形式存儲(chǔ)元素的。HashMap 需要一個(gè)hash函數(shù)立哑,它使用 hashCode()和 equals()方法來(lái)向集合/從集合添加和檢索元素夜惭。當(dāng)調(diào)用 put()方法的時(shí)候,HashMap會(huì)計(jì)算 key 的 hash 值铛绰,然后把鍵值對(duì)存儲(chǔ)在集合中合適的索引上诈茧。如果 key 已經(jīng)存在了,value 會(huì)被更新成新值捂掰。HashMap 的一些重要的特性是它的容量(capacity)敢会,負(fù)載因子(load factor)和擴(kuò)容極限(threshold resizing)曾沈。
9. hashCode() 和 equals() 方法的重要性體現(xiàn)在什么地方?
Java 中的 HashMap 使用 hashCode() 和 equals() 方法來(lái)確定鍵值對(duì)的索引鸥昏,當(dāng)根據(jù)鍵獲取值的時(shí)候也會(huì)用到這兩個(gè)方法塞俱。如果沒(méi)有正確的實(shí)現(xiàn)這兩個(gè)方法,兩個(gè)不同的鍵可能會(huì)有相同的 hash 值互广,因此敛腌,可能會(huì)被集合認(rèn)為是相等的。而且惫皱,這兩個(gè)方法也用來(lái)發(fā)現(xiàn)重復(fù)元素像樊。所以這兩個(gè)方法的實(shí)現(xiàn)對(duì) HashMap 的精確性和正確性是至關(guān)重要的。
10. HashMap 和 Hashtable 有什么區(qū)別旅敷?
HashMap 和 Hashtable 都實(shí)現(xiàn)了 Map 接口生棍,因此很多特性非常相似。但是媳谁,他們有以下不同點(diǎn):
HashMap 允許鍵和值是 null涂滴,而 Hashtable 不允許鍵或者值是 null。
Hashtable 是同步的晴音,而 HashMap 不是柔纵。因此, HashMap 更適合于單線程環(huán)境锤躁,而 Hashtable 適合于多線程環(huán)境搁料。
HashMap 提供了可供應(yīng)用迭代的鍵的集合,因此系羞,HashMap 是快速失敗的郭计。另一方面,Hashtable 提供了對(duì)鍵的列舉(Enumeration)椒振。
一般認(rèn)為 Hashtable 是一個(gè)遺留的類(lèi)昭伸。
11. 數(shù)組(Array)和列表(ArrayList)有什么區(qū)別?什么時(shí)候應(yīng)該使用 Array 而不是 ArrayList澎迎?
下面列出了 Array 和 ArrayList 的不同點(diǎn):
Array 可以包含基本類(lèi)型和對(duì)象類(lèi)型庐杨,ArrayList 只能包含對(duì)象類(lèi)型。
Array 大小是固定的夹供,ArrayList 的大小是動(dòng)態(tài)變化的辑莫。
ArrayList 提供了更多的方法和特性,比如:addAll()罩引,removeAll(),iterator()等等枝笨。
對(duì)于基本類(lèi)型數(shù)據(jù)袁铐,集合使用自動(dòng)裝箱來(lái)減少編碼工作量揭蜒。但是,當(dāng)處理固定大小的基本數(shù)據(jù)類(lèi)型的時(shí)候剔桨,這種方式相對(duì)比較慢屉更。
12. ArrayList 和 LinkedList 有什么區(qū)別?
ArrayList 和 LinkedList 都實(shí)現(xiàn)了 List 接口洒缀,他們有以下的不同點(diǎn):
ArrayList 是基于索引的數(shù)據(jù)接口瑰谜,它的底層是數(shù)組。它可以以O(shè)(1)時(shí)間復(fù)雜度對(duì)元素進(jìn)行隨機(jī)訪問(wèn)树绩。與此對(duì)應(yīng)萨脑,LinkedList 是以元素列表的形式存儲(chǔ)它的數(shù)據(jù),每一個(gè)元素都和它的前一個(gè)和后一個(gè)元素鏈接在一起饺饭,在這種情況下渤早,查找某個(gè)元素的時(shí)間復(fù)雜度是O(n)。
相對(duì)于 ArrayList瘫俊,LinkedList 的插入鹊杖,添加,刪除操作速度更快扛芽,因?yàn)楫?dāng)元素被添加到集合任意位置的時(shí)候骂蓖,不需要像數(shù)組那樣重新計(jì)算大小或者是更新索引。
LinkedList 比 ArrayList 更占內(nèi)存川尖,因?yàn)?LinkedList 為每一個(gè)節(jié)點(diǎn)存儲(chǔ)了兩個(gè)引用登下,一個(gè)指向前一個(gè)元素,一個(gè)指向下一個(gè)元素空厌。
也可以參考 ArrayList vs. LinkedList庐船。
13. Comparable 和Comparator 接口是干什么的?列出它們的區(qū)別嘲更。
Java 提供了只包含一個(gè) compareTo() 方法的 Comparable 接口筐钟。這個(gè)方法可以個(gè)給兩個(gè)對(duì)象排序。具體來(lái)說(shuō)赋朦,它返回負(fù)數(shù)篓冲,0,正數(shù)來(lái)表明輸入對(duì)象小于宠哄,等于壹将,大于已經(jīng)存在的對(duì)象。
Java 提供了包含 compare() 和 equals() 兩個(gè)方法的 Comparator 接口毛嫉。compare() 方法用來(lái)給兩個(gè)輸入?yún)?shù)排序诽俯,返回負(fù)數(shù),0承粤,正數(shù)表明第一個(gè)參數(shù)是小于暴区,等于闯团,大于第二個(gè)參數(shù)。equals() 方法需要一個(gè)對(duì)象作為參數(shù)仙粱,它用來(lái)決定輸入?yún)?shù)是否和 comparator 相等房交。只有當(dāng)輸入?yún)?shù)也是一個(gè) comparator 并且輸入?yún)?shù)和當(dāng)前 comparator 的排序結(jié)果是相同的時(shí)候,這個(gè)方法才返回 true伐割。
14. Java集合類(lèi)框架的最佳實(shí)踐有哪些候味?
根據(jù)應(yīng)用的需要正確選擇要使用的集合的類(lèi)型對(duì)性能非常重要,比如:假如元素的大小是固定的隔心,而且能事先知道白群,我們就應(yīng)該用 Array 而不是 ArrayList。
有些集合類(lèi)允許指定初始容量济炎。因此川抡,如果我們能估計(jì)出存儲(chǔ)的元素的數(shù)目,我們可以設(shè)置初始容量來(lái)避免重新計(jì)算 hash 值或者是擴(kuò)容须尚。
為了類(lèi)型安全崖堤,可讀性和健壯性的原因總是要使用泛型。同時(shí)耐床,使用泛型還可以避免運(yùn)行時(shí)的 ClassCastException密幔。
使用 JDK 提供的不變類(lèi)(immutable class)作為Map的鍵可以避免為我們自己的類(lèi)實(shí)現(xiàn) hashCode() 和 equals() 方法。
編程的時(shí)候接口優(yōu)于實(shí)現(xiàn)撩轰。
底層的集合實(shí)際上是空的情況下胯甩,返回長(zhǎng)度是0的集合或者是數(shù)組,不要返回 null堪嫂。
15. Enumeration 接口和 Iterator 接口的區(qū)別有哪些偎箫?
Enumeration 速度是 Iterator 的2倍,同時(shí)占用更少的內(nèi)存皆串。但是淹办,Iterator 遠(yuǎn)遠(yuǎn)比 Enumeration 安全,因?yàn)槠渌€程不能夠修改正在被 iterator 遍歷的集合里面的對(duì)象恶复。同時(shí)怜森,Iterator 允許調(diào)用者刪除底層集合里面的元素,這對(duì) Enumeration 來(lái)說(shuō)是不可能的谤牡。
16. HashSet 和 TreeSet 有什么區(qū)別副硅?
HashSet 是由一個(gè) hash 表來(lái)實(shí)現(xiàn)的,因此翅萤,它的元素是無(wú)序的恐疲。add(),remove(),contains()方法的時(shí)間復(fù)雜度是 O(1)培己。
另一方面糜烹,TreeSet 是由一個(gè)樹(shù)形的結(jié)構(gòu)來(lái)實(shí)現(xiàn)的,它里面的元素是有序的漱凝。因此,add()诸迟,remove()茸炒,contains() 方法的時(shí)間復(fù)雜度是 O(logn)。
17. List阵苇、Set壁公、Map 是否繼承自 Collection 接口?
答:List绅项、Set 是紊册,Map 不是。Map 是鍵值對(duì)映射容器快耿,與 List 和 Set 有明顯的區(qū)別囊陡,而 Set 存儲(chǔ)的零散的元素且不允許有重復(fù)元素(數(shù)學(xué)中的集合也是如此),List 是線性結(jié)構(gòu)的容器掀亥,適用于按數(shù)值索引訪問(wèn)元素的情形撞反。
18. 說(shuō)出 ArrayList、Vector搪花、LinkedList 的存儲(chǔ)性能和特性遏片?
答:ArrayList 和 Vector 都是使用數(shù)組方式存儲(chǔ)數(shù)據(jù),此數(shù)組元素?cái)?shù)大于實(shí)際存儲(chǔ)的數(shù)據(jù)以便增加和插入元素撮竿,它們都允許直接按序號(hào)索引元素吮便,但是插入元素要涉及數(shù)組元素移動(dòng)等內(nèi)存操作,所以索引數(shù)據(jù)快而插入數(shù)據(jù)慢幢踏,Vector 由于使用了 synchronized 方法(線程安全)髓需,通常性能上較 ArrayList 差,而 LinkedList 使用雙向鏈表實(shí)現(xiàn)存儲(chǔ)(將內(nèi)存中零散的內(nèi)存單元通過(guò)附加的引用關(guān)聯(lián)起來(lái)惑折,形成一個(gè)可以按序號(hào)索引的線性結(jié)構(gòu)授账,這種鏈?zhǔn)酱鎯?chǔ)方式與數(shù)組的連續(xù)存儲(chǔ)方式相比,其實(shí)對(duì)內(nèi)存的利用率更高)惨驶,按序號(hào)索引數(shù)據(jù)需要進(jìn)行前向或后向遍歷白热,但是插入數(shù)據(jù)時(shí)只需要記錄本項(xiàng)的前后項(xiàng)即可,所以插入速度較快粗卜。
Vector 屬于遺留容器(早期的 JDK 中使用的容器屋确,除此之外 Hashtable、Dictionary、BitSet攻臀、Stack焕数、Properties 都是遺留容器),現(xiàn)在已經(jīng)不推薦使用刨啸,但是由于 ArrayList 和 LinkedListed 都是非線程安全的堡赔,如果需要多個(gè)線程操作同一個(gè)容器,那么可以通過(guò)工具類(lèi) Collections 中的 synchronizedList 方法將其轉(zhuǎn)換成線程安全的容器后再使用(這其實(shí)是裝潢模式最好的例子设联,將已有對(duì)象傳入另一個(gè)類(lèi)的構(gòu)造器中創(chuàng)建新的對(duì)象來(lái)增加新功能)善已。
19. List、Map离例、Set 三個(gè)接口存儲(chǔ)元素時(shí)各有什么特點(diǎn)换团?
答:
1)List 是有序的 Collection,使用此接口能夠精確的控制每個(gè)元素插入的位置宫蛆。用戶能夠使用索引(元素在 List 中的位置艘包,類(lèi)似于數(shù)組下標(biāo))來(lái)訪問(wèn) List 中的元素,這類(lèi)似于 Java 的數(shù)組耀盗。
2)Set 是一種不包含重復(fù)的元素的 Collection想虎,即任意的兩個(gè)元素 e1 和 e2 都有e1.equals(e2)=false,Set 最多有一個(gè) null 元素袍冷。
3)Map 接口 :請(qǐng)注意磷醋,Map 沒(méi)有繼承 Collection 接口,Map 提供 key 到 value 的映射
20. 判斷下列語(yǔ)句是否正確胡诗,如果有錯(cuò)誤邓线,請(qǐng)指出錯(cuò)誤所在?
List<Short> a = new ArrayList<Short>();
a.add(5);
答:錯(cuò)誤,默認(rèn)封裝 int 類(lèi)型煌恢。
21. 你是怎么理解 Java 泛型的骇陈?
答: 在 Java SE 1.5之前,沒(méi)有泛型的情況的下瑰抵,通過(guò)對(duì)類(lèi)型 Object 的引用來(lái)實(shí)現(xiàn)參數(shù)的“任意化”你雌,“任意化”帶來(lái)的缺點(diǎn)是要做顯式的強(qiáng)制類(lèi)型轉(zhuǎn)換,而這種轉(zhuǎn)換是要求開(kāi)發(fā)者對(duì)實(shí)際參數(shù)類(lèi)型可以預(yù)知的情況下進(jìn)行的二汛。對(duì)于強(qiáng)制類(lèi)型轉(zhuǎn)換錯(cuò)誤的情況婿崭,編譯器可能不提示錯(cuò)誤,在運(yùn)行的時(shí)候才出現(xiàn)異常肴颊,這是一個(gè)安全隱患氓栈。
泛型是 Java SE 1.5的新特性,泛型的本質(zhì)是參數(shù)化類(lèi)型婿着,也就是說(shuō)所操作的數(shù)據(jù)類(lèi)型被指定為一個(gè)參數(shù)授瘦。這種參數(shù)類(lèi)型可以用在類(lèi)醋界、接口和方法的創(chuàng)建中,分別稱(chēng)為泛型類(lèi)提完、泛型接口形纺、泛型方法。
泛型的好處是在編譯的時(shí)候檢查類(lèi)型安全徒欣,并且所有的強(qiáng)制轉(zhuǎn)換都是自動(dòng)和隱式的逐样,提高代碼的重用率。