先來看看集合的繼承關係圖,以下圖所示:java
其中:git
爲了方便理解,我隱藏了一些與本文內容無關的信息,隱藏的這些內容會在後面的章節中進行詳細地介紹。面試
從圖中能夠看出,集合的根節點是 Collection,而 Collection 下又提供了兩大經常使用集合,分別是:算法
下面咱們分別對集合類進行詳細地介紹。數組
Vector 是 Java 早期提供的線程安全的有序集合,若是不須要線程安全,不建議使用此集合,畢竟同步是有線程開銷的。安全
使用示例代碼:數據結構
Vector vector = new Vector(); vector.add("dog"); vector.add("cat"); vector.remove("cat"); System.out.println(vector);
程序執行結果:[dog]
ide
ArrayList 是最多見的非線程安全的有序集合,由於內部是數組存儲的,因此隨機訪問效率很高,但非尾部的插入和刪除性能較低,若是在中間插入元素,以後的全部元素都要後移。ArrayList 的使用與 Vector 相似。函數
LinkedList 是使用雙向鏈表數據結構實現的,所以增長和刪除效率比較高,而隨機訪問效率較差。性能
LinkedList 除了包含以上兩個類的操做方法以外,還新增了幾個操做方法,如 offer() 、peek() 等,具體詳情,請參考如下代碼:
LinkedList linkedList = new LinkedList(); // 添加元素 linkedList.offer("bird"); linkedList.push("cat"); linkedList.push("dog"); // 獲取第一個元素 System.out.println(linkedList.peek()); // 獲取第一個元素,並刪除此元素 System.out.println(linkedList.poll()); System.out.println(linkedList);
程序的執行結果:
dog dog [cat, bird]
HashSet 是一個沒有重複元素的集合。雖然它是 Set 集合的子類,實際卻爲 HashMap 的實例,相關源碼以下:
public HashSet() { map = new HashMap<>(); }
所以 HashSet 是無序集合,沒有辦法保證元素的順序性。
HashSet 默認容量爲 16,每次擴充 0.75 倍,相關源碼以下:
public HashSet(Collection\<? extends E\> c) { map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c); }
HashSet 的使用與 Vector 相似。
TreeSet 集合實現了自動排序,也就是說 TreeSet 會把你插入數據進行自動排序。
示例代碼以下:
TreeSet treeSet = new TreeSet(); treeSet.add("dog"); treeSet.add("camel"); treeSet.add("cat"); treeSet.add("ant"); System.out.println(treeSet);
程序執行結果:[ant, camel, cat, dog]
能夠看出,TreeSet 的使用與 Vector 相似,只是實現了自動排序。
LinkedHashSet 是按照元素的 hashCode 值來決定元素的存儲位置,但同時又使用鏈表來維護元素的次序,這樣使得它看起來像是按照插入順序保存的。
LinkedHashSet 的使用與 Vector 相似。
集合和數組的轉換可以使用 toArray() 和 Arrays.asList() 來實現,請參考如下代碼示例:
List<String> list = new ArrayList(); list.add("cat"); list.add("dog"); // 集合轉數組 String[] arr = list.toArray(new String[list.size()]); // 數組轉集合 List<String> list2 = Arrays.asList(arr);
集合與數組的區別,能夠參考「數組和排序算法的應用 + 面試題」的內容。
在 Java 語言中排序提供了兩種方式:Comparable 和 Comparator,它們的區別也是常見的面試題之一。下面咱們完全地來了解一下 Comparable 和 Comparator 的使用與區別。
Comparable 位於 java.lang 包下,是一個排序接口,也就是說若是一個類實現了 Comparable 接口,就意味着該類有了排序功能。
Comparable 接口只包含了一個函數,定義以下:
package java.lang; import java.util.*; public interface Comparable { public int compareTo(T o); }
Comparable 使用示例,請參考如下代碼:
class ComparableTest { public static void main(String[] args) { Dog[] dogs = new Dog[]{ new Dog("老旺財", 10), new Dog("小旺財", 3), new Dog("二旺財", 5), }; // Comparable 排序 Arrays.sort(dogs); for (Dog d : dogs) { System.out.println(d.getName() + ":" + d.getAge()); } } } class Dog implements Comparable\<Dog\> { private String name; private int age; @Override public int compareTo(Dog o) { return age - o.age; } public Dog(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } }
程序執行結果:
小旺財:3 二旺財:5 老旺財:10
若是 Dog 類未實現 Comparable 執行代碼會報程序異常的信息,錯誤信息爲:
Exception in thread "main" java.lang.ClassCastException: xxx cannot be cast to java.lang.ComparablecompareTo() 返回值有三種:
Comparator 是一個外部比較器,位於 java.util 包下,之因此說 Comparator 是一個外部比較器,是由於它無需在比較類中實現 Comparator 接口,而是要新建立一個比較器類來進行比較和排序。
Comparator 接口包含的主要方法爲 compare(),定義以下:
public interface Comparator\<T\> { int compare(T o1, T o2); }
Comparator 使用示例,請參考如下代碼:
class ComparatorTest { public static void main(String[] args) { Dog[] dogs = new Dog[]{ new Dog("老旺財", 10), new Dog("小旺財", 3), new Dog("二旺財", 5), }; // Comparator 排序 Arrays.sort(dogs,new DogComparator()); for (Dog d : dogs) { System.out.println(d.getName() + ":" + d.getAge()); } } } class DogComparator implements Comparator\<Dog\> { @Override public int compare(Dog o1, Dog o2) { return o1.getAge() - o2.getAge(); } } class Dog { private String name; private int age; public Dog(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } }
程序執行結果:
小旺財:3 二旺財:5 老旺財:10
答:區別分爲如下幾個方面:
答:TreeSet 集合實現了元素的自動排序,也就是說無需任何操做,便可實現元素的自動排序功能。
答:Vector 和 ArrayList 的默認容量都爲 10,源碼以下。
Vector 默認容量源碼:
public Vector() { this(10); }
ArrayList 默認容量源碼:
private static final int DEFAULT_CAPACITY = 10;
Vector 容量擴充默認增長 1 倍,源碼以下:
private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity); }
其中 capacityIncrement 爲初始化 Vector 指定的,默認狀況爲 0。
ArrayList 容量擴充默認增長大概 0.5 倍(oldCapacity + (oldCapacity >> 1)),源碼以下(JDK 8):
private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); }
答:這三者都是 List 的子類,所以功能比較類似,好比增長和刪除操做、查找元素等,但在性能、線程安全等方面表現卻又不相同,差別以下:
答:Vector 和 ArrayList 的內部結構是以數組形式存儲的,所以很是適合隨機訪問,但非尾部的刪除或新增性能較差,好比咱們在中間插入一個元素,就須要把後續的全部元素都進行移動。
LinkedList 插入和刪除元素效率比較高,但隨機訪問性能會比以上兩個動態數組慢。
答:Collection 和 Collections 的區別以下:
A:List
B:Set
C:Map
D:HashSet
答:C
答:LinkedHashSet 底層數據結構由哈希表和鏈表組成,鏈表保證了元素的有序即存儲和取出一致,哈希表保證了元素的惟一性。
答:HashSet 的底層其實就是 HashMap,只不過 HashSet 實現了 Set 接口而且把數據做爲 K 值,而 V 值一直使用一個相同的虛值來保存,咱們能夠看到源碼:
public boolean add(E e) { return map.put(e, PRESENT)==null;// 調用 HashMap 的 put 方法,PRESENT 是一個至始至終都相同的虛值 }
因爲 HashMap 的 K 值自己就不容許重複,而且在 HashMap 中若是 K/V 相同時,會用新的 V 覆蓋掉舊的 V,而後返回舊的 V,那麼在 HashSet 中執行這一句話始終會返回一個 false,致使插入失敗,這樣就保證了數據的不可重複性。
Integer num = 10; Integer num2 = 5; System.out.println(num.compareTo(num2));
答:程序輸出的結果是 1
,由於 Integer 默認實現了 compareTo 方法,定義了天然排序規則,因此當 num 比 num2 大時會返回 1,Integer 相關源碼以下:
public int compareTo(Integer anotherInteger) { return compare(this.value, anotherInteger.value); } public static int compare(int x, int y) { return (x < y) ? -1 : ((x == y) ? 0 : 1); }
答:可使用集合中的 Stack 實現,Stack 是標準的後進先出的棧結構,使用 Stack 中的 pop() 方法返回棧頂元素並刪除該元素,示例代碼以下。
Stack stack = new Stack(); stack.push("a"); stack.push("b"); stack.push("c"); for (int i = 0; i < 3; i++) { // 移除並返回棧頂元素 System.out.print(stack.pop() + " "); }
程序執行結果:c b a
答:peek() 方法返回第一個元素,但不刪除當前元素,當元素不存在時返回 null;poll() 方法返回第一個元素並刪除此元素,當元素不存在時返回 null。
答:Comparable 和 Comparator 的主要區別以下:
本文介紹的集合都實現自 Collection,所以它們都有一樣的操做方法,如 add()、addAll()、remove() 等,Collection 接口的方法列表以下圖:
固然部分集合也在原有方法上擴充了本身特有的方法,如 LinkedList 的 offer()、push() 等方法。本文也提供了數組和集合互轉方法,List.toArray() 把集合轉換爲數組,Arrays.asList(array) 把數組轉換爲集合。最後介紹了 Comparable 和 Comparator 的使用和區別,Comparable 和 Comparator 是 Java 語言排序提供的兩種排序方式,Comparable 位於 java.lang 包下,若是一個類實現了 Comparable 接口,就意味着該類有了排序功能;而 Comparator 位於 java.util 包下,是一個外部比較器,它無需在比較類中實現 Comparator 接口,而是要新建立一個比較器類來進行比較和排序。
_
歡迎關注個人公衆號,回覆關鍵字「Java」 ,將會有大禮相送!!! 祝各位面試成功!!!