Java中的集合概述
Java中的集合類有兩個重要的分支,分別是接口Collection(包括List,Set等)和接口Map。
由於HashSet的內部實現原理使用了HashMap,所以我們先來了解Map集合類。
1.HashMap、Hashtable和TreeMap
(1)java.lang.Object
繼承者 java.util.AbstractMap<K,V>
繼承者 java.util.HashMap<K,V>
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable
(2)java.lang.Object
繼承者 java.util.Dictionary<K,V>
繼承者 java.util.Hashtable<K,V>
public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, Serializable
(3)java.lang.Object
繼承者 java.util.AbstractMap<K,V>
繼承者 java.util.TreeMap<K,V>
public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>, Cloneable, Serializable
其中,HashMap不是線程
安全的;HashTable是線程安全的,其線程安全是通過sychronize實現的。基於該原因,HashMap效率高於HashTable。
HashMap的鍵可以為null,HashTable不可以。
在多線程環境下,HashMap配合Collections工具類使用來實現線程安全;還可以選擇ConcurrentHashMap,該類的線程安全是通過Lock的方式實現的,所以效率高於Hashtable。
數組,鏈表,哈希表,三者各有優劣。數組使用連續的內存空間,查找速度快,增刪慢;鏈表充分利用了內存,存儲空間是不連續的,首尾各存儲上下一個節點的信息,所以尋址較慢,即查找速度慢,但是增刪快;哈希表綜合了前二者的優點,一個哈希表,由數組和鏈表組成。假設一條鏈表有1000個節點,現在要查找最後一個節點,就得從第一個遍歷到最後一個;如果用哈希表,將這條鏈表分為10組,用一個容量為10的數組來存儲這10組鏈表的頭結點(a[0] = 0 , a[1] = 100 , a[2] = 200 …以此類推),這樣的話就明顯提高了尋址效率。
HashMap就是基於上述哈希表原理實現的尋址,Hashtable同理,只不過做了同步處理。
HashMap輸出是無序的,這個無序不是說每次遍歷的結果順序不一樣,而是說與插入順序不一樣
另外,TreeMap是按鍵排序的,默認升序,所以可以通過TreeMap來實現。TreeMap的排序是在底層基於比較器(Comparator接口的int compare(T o1,T o2),Comaparable接口的int compareTo(T o))實現的。
HashMap實現線程同步的方式有兩種,一種是:
Map<Integer , String> hs = new HashMap<Integer , String>(); hs = Collections.synchronizedMap(hs);
另一種是:
ConcurrentHashMap<Integer , String> hs = new ConcurrentHashMap<Integer , String>();
2.List接口及其子類ArrayList,LinkedList,Vector,Stack。
public interface List<E> extends Collection<E>
(1)java.lang.Object
繼承者 java.util.AbstractCollection<E>
繼承者 java.util.AbstractList<E>
繼承者 java.util.ArrayList<E>
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable
(2)java.lang.Object
繼承者 java.util.AbstractCollection<E>
繼承者 java.util.AbstractList<E>
繼承者 java.util.AbstractSequentialList<E>
繼承者 java.util.LinkedList<E>
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, Serializable
(3)java.lang.Object
繼承者 java.util.AbstractCollection<E>
繼承者 java.util.AbstractList<E>
繼承者 java.util.Vector<E>
public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable
(4)java.lang.Object
繼承者 java.util.AbstractCollection<E>
繼承者 java.util.AbstractList<E>
繼承者 java.util.Vector<E>
繼承者 java.util.Stack<E>
public class Stack<E> extends Vector<E>
其中,ArrayList和Vector本質都是用數組實現的,而LinkList是用雙鏈表實現的。所以,Arraylist和Vector在查找效率上比較高,增刪效率比較低;LinkedList則正好相反。
ArrayList是線程不安全的,Vector是線程安全的,在效率沒有ArrayList高。實際使用中,一般也不怎麽用Vector,可以自己做線程同步,也可以用Collections配合ArrayList實現線程同步。
在排序上,List是使用Collections類的sort方法,構造Comparator或者讓List中的對象實現Comparable都可以。
Stack繼承自Vector,在用法、線程安全方面的跟Vector都差不多,有幾個地方需要註意,一是add()和push(),stack是將最後一個element作為棧頂的,add()返回boolean,就是添加成功了沒有,push()返回的是添加的元素,一般推薦使用push;二是peek()和pop(),這兩個方法都能得到棧頂元素,區別是peek()只是讀取,對原棧沒有什麽影響,pop()從字面上就能理解為“出棧”,所以原棧的棧頂元素就沒了。
3.Set接口及其子類HashSet,TreeSet。
public interface Set<E> extends Collection<E>
(1)java.lang.Object
繼承者 java.util.AbstractCollection<E>
繼承者 java.util.AbstractSet<E>
繼承者 java.util.HashSet<E>
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, Serializable
(2)java.lang.Object
繼承者 java.util.AbstractCollection<E>
繼承者 java.util.AbstractSet<E>
繼承者 java.util.TreeSet<E>
public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, Serializable
總的來說,Set集合類的特點是可以去重,它們的內部實現都是基於Map的,用的是Map的key,而Map的key是不可以重復的。既然要去重,就需要比較,而比較是基於hascode()方法和equals()方法的。
Java中的集合概述