【容器】
18. Java 容器都有哪些?
19. Collection 和 Collections 有什么區別?
- Collection 是一個集合接口,它提供了對集合對象進行基本操作的通用接口方法,所有集合都是它的子類,比如 List、Set 等。
- Collections 是一個包裝類,包含了很多靜態方法,不能被實例化,就像一個工具類,比如提供的排序方法: Collections. sort(list)。
20. List、Set、Map 之間的區別是什么?
List、Set、Map 的區別主要體現在兩個方面:元素是否有序、是否允許元素重復。
三者之間的區別,如下表:
21. HashMap 和 Hashtable 有什么區別?
- 存儲:HashMap 允許 key 和 value 為 null,而 Hashtable 不允許。
- 線程安全:Hashtable 是線程安全的,而 HashMap 是非線程安全的。
- 推薦使用:在 Hashtable 的類注釋可以看到,Hashtable 是保留類不建議使用,推薦在單線程環境下使用 HashMap 替代,如果需要多線程使用則用 ConcurrentHashMap 替代。
22. 如何決定使用 HashMap 還是 TreeMap?
對於在 Map 中插入、刪除、定位一個元素這類操作,HashMap 是最好的選擇,因為相對而言 HashMap 的插入會更快,但如果你要對一個 key 集合進行有序的遍歷,那 TreeMap 是更好的選擇。
23. 說一下 HashMap 的實現原理?
HashMap 基於 Hash 算法實現的,我們通過 put(key,value)存儲,get(key)來獲取。當傳入 key 時,HashMap 會根據 key. hashCode() 計算出 hash 值,根據 hash 值將 value 保存在 bucket 里。當計算出的 hash 值相同時,我們稱之為 hash 沖突,HashMap 的做法是用鏈表和紅黑樹存儲相同 hash 值的 value。當 hash 沖突的個數比較少時,使用鏈表否則使用紅黑樹。(注:使用紅黑樹是在jdk1.8之后做的改進)
24. 說一下 HashSet 的實現原理?
HashSet 是基於 HashMap 實現的,HashSet 底層使用 HashMap 來保存所有元素,因此 HashSet 的實現比較簡單,相關 HashSet 的操作,基本上都是直接調用底層 HashMap 的相關方法來完成,HashSet 不允許重復的值。
25. ArrayList 和 LinkedList 的區別是什么?
- 數據結構實現:ArrayList 是動態數組的數據結構實現,而 LinkedList 是雙向鏈表的數據結構實現。
- 隨機訪問效率:ArrayList 比 LinkedList 在隨機訪問的時候效率要高,因為 LinkedList 是線性的數據存儲方式,所以需要移動指針從前往后依次查找。
- 增加和刪除效率:在非首尾的增加和刪除操作,LinkedList 要比 ArrayList 效率要高,因為 ArrayList 增刪操作要影響數組內的其他數據的下標。
綜合來說,在需要頻繁讀取集合中的元素時,更推薦使用 ArrayList,而在插入和刪除操作較多時,更推薦使用 LinkedList。
26. 如何實現數組和 List 之間的轉換?
- 數組轉 List:使用 Arrays. asList(array) 進行轉換。
- List 轉數組:使用 List 自帶的 toArray() 方法。
代碼示例:
// list to array List<String> list = new ArrayList<String>(); list.add("akon"); list.add("blog"); list.toArray(); // array to list String[] array = new String[]{"akon","blog"}; Arrays.asList(array);
27. ArrayList 和 Vector 的區別是什么?
線程安全:Vector 使用了 Synchronized 來實現線程同步,是線程安全的,而 ArrayList 是非線程安全的。
性能:ArrayList 在性能方面要優於 Vector。
擴容:ArrayList 和 Vector 都會根據實際的需要動態的調整容量,只不過在 Vector 擴容每次會增加 1 倍,而 ArrayList 只會增加 50%。
28. Array 和 ArrayList 有何區別?
Array 可以存儲基本數據類型和對象,ArrayList 只能存儲對象。
Array 是指定固定大小的,而 ArrayList 大小是自動擴展的。
Array 內置方法沒有 ArrayList 多,比如 addAll、removeAll、iteration 等方法只有 ArrayList 有。
29. 在 Queue 中 poll()和 remove()有什么區別?
相同點:都是返回第一個元素,並在隊列中刪除返回的對象。
不同點:如果沒有元素 poll()會返回 null,而 remove()會直接拋出 NoSuchElementException 異常。
代碼示例:
Queue<String> queue = new LinkedList<String>(); queue.offer("string"); // add System.out.println(queue.poll()); System.out.println(queue.remove()); System.out.println(queue.size());
30. 哪些集合類是線程安全的?
Vector、Hashtable、Stack 都是線程安全的,而像 HashMap 則是非線程安全的,不過在 JDK 1.5 之后隨着 Java. util. concurrent 並發包的出現,它們也有了自己對應的線程安全類,比如 HashMap 對應的線程安全類就是 ConcurrentHashMap。
31. 迭代器 Iterator 是什么?
Iterator 接口提供遍歷任何 Collection 的接口。我們可以從一個 Collection 中使用迭代器方法來獲取迭代器實例。迭代器取代了 Java 集合框架中的 Enumeration,迭代器允許調用者在迭代過程中移除元素。
32. Iterator 怎么使用?有什么特點?
Iterator 使用代碼如下:
List<String> list = new ArrayList<>(); Iterator<String> it = list. iterator(); while(it. hasNext()){ String obj = it. next(); System.out.println(obj); }
Iterator 的特點是更加安全,因為它可以確保,在當前遍歷的集合元素被更改的時候,就會拋出 ConcurrentModificationException 異常。
33. Iterator 和 ListIterator 有什么區別?
Iterator 可以遍歷 Set 和 List 集合,而 ListIterator 只能遍歷 List。
Iterator 只能單向遍歷,而 ListIterator 可以雙向遍歷(向前/后遍歷)。
ListIterator 從 Iterator 接口繼承,然后添加了一些額外的功能,比如添加一個元素、替換一個元素、獲取前面或后面元素的索引位置。
34. 怎么確保一個集合不能被修改?
可以使用 Collections. unmodifiableCollection(Collection c) 方法來創建一個只讀集合,這樣改變集合的任何操作都會拋出 Java.lang.UnsupportedOperationException 異常。
示例代碼如下:
List<String> list = new ArrayList<>(); list.add("x"); Collection<String> clist = Collections.unmodifiableCollection(list); clist.add("y"); // 運行時此行報錯 System.out.println(list.size());