中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

每周10道Java面試題:集合類

2019-01-03    來源:importnew

容器云強勢上線!快速搭建集群,上萬Linux鏡像隨意使用

每周10道?Java?面試題由 ImportNew 整理編譯自網(wǎng)絡。
面試題答案討論請移步:https://github.com/jobbole/java-interview/issues/1
Java面試題投遞交流請移步:https://github.com/jobbole/java-interview/issues/2

1. 你了解哪些集合類型?

答案:你應該知道以下幾個最重要的類型:

  • ArrayList
  • LinkedList
  • HashMap
  • HashSet

之后,你可能會被問到這樣一些問題,比如應該何時使用此種特定類型,它比其他的好在哪里,它是怎么存儲數(shù)據(jù)的以及隱匿在背后的數(shù)據(jù)結構是什么。最好的方法是盡可能多地了解這些集合類型,因為這類問題幾乎是無窮盡的。

2. HashMap 有什么特點?
答案:HashMap 基于Map接口實現(xiàn),存儲鍵值對時,可以接收 null 為鍵值。HashMap 是非同步的。

3. HashMap 的工作原理是怎樣的?
答案:HashMap 在 Map.Entry 靜態(tài)內(nèi)部類實現(xiàn)中存儲鍵值對,使用哈希算法。在 put 和 get 方法中,使用 hashCode() 和 equals() 方法。

  • 調(diào)用 put 方法時,使用鍵值對中的 Key hashCode() 和哈希算法找出存儲鍵值對索引。鍵值對 Entry 存儲在 LinkedList 中,如果存在 Entry,使用 equals() 方法來檢查 Key 是否已經(jīng)存在:如果存在,則覆蓋 value;如果不存在,會創(chuàng)建一個新的 Entry 然后保存。
  • 調(diào)用 get 方法時,HashMap 使用鍵值 Key hashCode() 來找到數(shù)組中的索引,然后使用 equals() 方法找出正確的 Entry,返回 Entry 中的 Value。

分析:HashMap 中容量、負荷系數(shù)和閥值是重要的參數(shù)。HashMap 默認的初始容量是32,負荷系數(shù)是0.75閥值 = 負荷系數(shù) x 容量。添加 Entry時,如果 Map 的大小 > 閥值,HashMap 會對 Map 的內(nèi)容重新哈希,使用更大的容量(容量總是2的冪)。關于 JDK 中的 hash 算法實現(xiàn)以及由此引發(fā)的哈希碰撞現(xiàn)象(DDos攻擊)都可能是面試的延伸問題。

4. 能否使用任何類作為 Map 的 key?

答案:可以使用任何類作為 Map 的 key,然而在使用之前,需要考慮以下幾點:

  • 如果類重寫了 equals() 方法,也應該重寫 hashCode() 方法。
  • 類的所有實例需要遵循與 equals() 和 hashCode() 相關的規(guī)則。
  • 如果一個類沒有使用 equals(),不應該在 hashCode() 中使用它。
  • 用戶自定義 Key 類最佳實踐是使之為不可變的,這樣 hashCode() 值可以被緩存起來,擁有更好的性能。不可變的類也可以確保 hashCode() 和 equals() 在未來不會改變,這樣就會解決與可變相關的問題了。

分析:如果有一個類 MyKey,在 HashMap 中使用它:

HashMap<MyKey, String> myHashMap = new HashMap<MyKey, String>();

//傳遞給 MyKey 的 name 參數(shù)被用于 equals() 和 hashCode() 中
MyKey key = new MyKey("Pankaj"); // 假設 hashCode=1234
myHashMap.put(key, "Value");

// 以下的代碼會改變 key 的 hashCode() 和 equals() 值
key.setName("Amit"); // 假設新的 hashCode=7890

//下面會返回 null,因為 HashMap 會嘗試查找存儲同樣索引的 key,而 key 已被改變了,匹配失敗,返回 null
System.out.println(myHashMap.get(new MyKey("Pankaj")));

這就是為什么 String 通常會用作 HashMap 的 Key,因為 String 的設計是不可變的(immutable)。

5.?插入數(shù)據(jù)時,ArrayList、LinkedList、Vector誰速度較快?
答案:ArrayList、LinkedList、Vector 底層的實現(xiàn)都是使用數(shù)組方式存儲數(shù)據(jù)。數(shù)組元素數(shù)大于實際存儲的數(shù)據(jù)以便增加和插入元素,它們都允許直接按序號索引元素,但是插入元素要涉及數(shù)組元素移動等內(nèi)存操作,所以索引數(shù)據(jù)快而插入數(shù)據(jù)慢。

  • Vector 中的方法由于加了 synchronized 修飾,因此 Vector 是線程安全容器,但性能上較ArrayList差。
  • LinkedList 使用雙向鏈表實現(xiàn)存儲,按序號索引數(shù)據(jù)需要進行前向或后向遍歷,但插入數(shù)據(jù)時只需要記錄當前項的前后項即可,所以 LinkedList?插入速度較快。

6. 多線程場景下如何使用 ArrayList?
答案:
ArrayList 不是線程安全的,如果遇到多線程場景,可以通過 Collections 的 synchronizedList 方法將其轉(zhuǎn)換成線程安全的容器后再使用。例如像下面這樣:

List<String> synchronizedList = Collections.synchronizedList(list);
synchronizedList.add("aaa");
synchronizedList.add("bbb");
for (int i = 0; i < synchronizedList.size(); i++)
{
    System.out.println(synchronizedList.get(i));
}

7. 說一下 ArrayList 的優(yōu)缺點
答案:ArrayList的優(yōu)點如下:

  1. ArrayList 底層以數(shù)組實現(xiàn),是一種隨機訪問模式。ArrayList?實現(xiàn)了 RandomAccess 接口,因此查找的時候非?。
  2. ArrayList 在順序添加一個元素的時候非常方便。

ArrayList 的缺點如下:

  1. 刪除元素的時候,需要做一次元素復制操作。如果要復制的元素很多,那么就會比較耗費性能。
  2. 插入元素的時候,也需要做一次元素復制操作,缺點同上。

ArrayList 比較適合順序添加、隨機訪問的場景。

8.?為什么 ArrayList 的 elementData 加上 transient 修飾?
答案:ArrayList 中的數(shù)組定義如下:

private transient Object[] elementData;

再看一下 ArrayList 的定義:

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

可以看到 ArrayList 實現(xiàn)了 Serializable 接口,這意味著 ArrayList 支持序列化。transient 的作用是說不希望 elementData 數(shù)組被序列化,重寫了?writeObject 實現(xiàn):

private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException{
	// Write out element count, and any hidden stuff
	int expectedModCount = modCount;
	s.defaultWriteObject();
        // Write out array length
	s.writeInt(elementData.length);
        // Write out all elements in the proper order.
	for (int i=0; i<size; i++)
	    s.writeObject(elementData[i]);
	if (modCount != expectedModCount) {
	    throw new ConcurrentModificationException();
	}

每次序列化時,先調(diào)用 defaultWriteObject() 方法序列化 ArrayList 中的非 transient 元素,然后遍歷 elementData,只序列化已存入的元素,這樣既加快了序列化的速度,又減小了序列化之后的文件大小。

9.?遍歷一個 List 有哪些不同的方式?每種方法的實現(xiàn)原理是什么?Java 中 List 遍歷的最佳實踐是什么?
答案:
遍歷方式有以下幾種:

  1. for 循環(huán)遍歷,基于計數(shù)器。在集合外部維護一個計數(shù)器,然后依次讀取每一個位置的元素,當讀取到最后一個元素后停止。
  2. 迭代器遍歷,Iterator。Iterator 是面向?qū)ο蟮囊粋設計模式,目的是屏蔽不同數(shù)據(jù)集合的特點,統(tǒng)一遍歷集合的接口。Java 在 Collections 中支持了 Iterator 模式。
  3. foreach 循環(huán)遍歷。foreach 內(nèi)部也是采用了 Iterator 的方式實現(xiàn),使用時不需要顯式聲明 Iterator 或計數(shù)器。優(yōu)點是代碼簡潔,不易出錯;缺點是只能做簡單的遍歷,不能在遍歷過程中操作數(shù)據(jù)集合,例如刪除、替換。

最佳實踐:Java Collections?框架中提供了一個 RandomAccess 接口,用來標記 List 實現(xiàn)是否支持 Random Access。

  • 如果一個數(shù)據(jù)集合實現(xiàn)了該接口,就意味著它支持 Random Access,按位置讀取元素的平均時間復雜度為 O(1),如ArrayList。
  • 如果沒有實現(xiàn)該接口,表示不支持 Random Access,如LinkedList。

推薦的做法就是,支持 Random Access 的列表可用 for 循環(huán)遍歷,否則建議用 Iterator 或 foreach 遍歷。

10.?如何邊遍歷邊移除 Collection 中的元素?
答案:
邊遍歷邊修改 Collection 的唯一正確方式是使用?Iterator.remove()?方法,如下:

Iterator<Integer> it = list.iterator();
while(it.hasNext()){
    // do something
    it.remove();
}

一種最常見的錯誤代碼如下:

for(Integer i : list){
    list.remove(i)
}

運行以上錯誤代碼會報?ConcurrentModificationException?異常。這是因為當使用?foreach(for(Integer i : list)) 語句時,會自動生成一個iterator 來遍歷該 list,但同時該 list 正在被?Iterator.remove()?修改。Java 一般不允許一個線程在遍歷 Collection 時另一個線程修改它。

關于作者: 唐尤華

唐尤華

我喜歡程序員,他們單純、固執(zhí)、容易體會到成就感;面對壓力,能夠挑燈夜戰(zhàn)不眠不休;面對困難,能夠迎難而上挑戰(zhàn)自我。他們也會感到困惑與傍徨,但每個程序員的心中都有一個比爾蓋茨或是喬布斯的夢想“用智慧開創(chuàng)屬于自己的事業(yè)”。我想說的是,其實我是一個程序員。(新浪微博:@唐尤華

查看唐尤華的更多文章 >>

標簽: ddos 安全 代碼 網(wǎng)絡

版權申明:本站文章部分自網(wǎng)絡,如有侵權,請聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點!
本站所提供的圖片等素材,版權歸原作者所有,如需使用,請與原作者聯(lián)系。

上一篇:Java HashMap源碼分析

下一篇:JVM基礎面試題及原理講解