sethtml
Set不按特定方式進行排序,而且沒有重複的對象,它的有些實現類能對集合中的對象按照特定的順序排序。主要有兩個實現類:HashSet和TreeSetjava
HashSet按照哈希算法來存取集合中的對象,存取速度比較快。程序員
TreeSet實現了SortSet接口,具備排序功能。算法
Listapi
List主要特徵是以線性方式存儲,集合中容許存放重複對象主要實現類包括ArrayList和LinkList數組
ArrayList表明長度可變的數組,容許對元素進行快速的隨機訪問,可是向ArrayList中插入與刪除元素較慢。安全
LinkList在實現中採用鏈表的結構,插入和刪除元素較快,隨機訪問則相對較慢。多線程
LinkList單獨具備addFirst(),addLast(),getFirst(),getLast(),removeFirst(),removeLast()等方法這些方法使得LinkList能夠做爲堆棧,隊列和雙向隊列使用併發
Queue框架
Queue隊列中的對象按照先進先出的規則來排列。在隊列末尾添加元素,在隊列的頭部刪除元素。能夠有重複對象。
雙向隊列Deque則容許在隊列的尾部和頭部添加和刪除元素。
由於LinkList能夠做爲雙向隊列使用,因此Queue和Deque使用比較少
Map
HashMap不保證映射的順序,特別是它不保證該順序恆久不變。(也就是無序)
TreeMapTreeMap基於紅黑樹(Red-Black tree)的 NavigableMap
實現,有序。
HashMap和TreeMap容許使用 null 值和 null 鍵 。
HashMap是使用hashCode和equals方法去重的。而TreeMap依靠Comparable或Comparator來實現key去重
在java集合框架中,Set List Queue Map的實現類都沒有采起同步機制。在單線程環境中,這種實現方式會提升操縱集合的效率,java虛擬機沒必要會由於管理用不鎖而產生額外的開銷。
在多線程環境中,可能會有多個線程同時操縱一個集合,好比一個線程在爲集合排序,而另一個線程正不斷的向集合中添加新的元素。
爲了不併發問題,能夠直接採用java.util.concurrent併發包提供線程安全的集合。列如
ConcurrentHashMap 、ConcurrentSkipListMap、ConcurrentSkipListSet和ConcurrentLinkedQueue。
這些集合的底層實現採用了複雜的算法,保證多線程訪問集合時,既能保證線程之間的同步,又具備高效的併發性能。
Hashtable:
Hashtable,用做鍵的對象必須實現 hashCode
方法和 equals
方法。容器使用synchronized來保證線程安全,但在線程競爭激烈的狀況下Hashtable的效率很是低下。由於當一個線程訪問Hashtable的同步方法時,其餘線程訪問Hashtable的同步方法,就可能會進入阻塞或輪詢狀態。
如線程1使用put進行添加元素,線程2不但不能使用put方法添加元素,而且也不能使用get方法來獲取元素,因此競爭越激烈效率越低。
歷史集合類 :Vector Hashtable Stack Enumeration 在實現中都採用了同步機制,併發性能較差,所以不提倡使用它們。
ConcurrentHashMap:
儘管全部操做都是線程安全的,但獲取操做不 必鎖定,而且不 支持以某種防止全部訪問的方式鎖定整個表。
容許經過可選的 concurrencyLevel 構造方法參數(默認值爲 16)來引導更新操做之間的併發,該參數用做內部調整大小的一個提示——摘自API
final V putVal(K key, V value, boolean onlyIfAbsent) { if (key == null || value == null) throw new NullPointerException(); //計算hash int hash = spread(key.hashCode()); int binCount = 0; for (Node<K,V>[] tab = table;;) { Node<K,V> f; int n, i, fh; //table是空的,進行初始化 if (tab == null || (n = tab.length) == 0) tab = initTable(); //若是當前索引位置沒有值,直接建立 else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) { //cas 在 i 位置建立新的元素,當 i 位置是空時,即能建立成功,結束for自循,不然繼續自旋 if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value, null))) break; // no lock when adding to empty bin } //若是當前槽點是轉移節點,表示該槽點正在擴容,就會一直等待擴容完成 //轉移節點的 hash 值是固定的,都是 MOVED else if ((fh = f.hash) == MOVED) tab = helpTransfer(tab, f); //槽點上有值的 else { V oldVal = null; //鎖定當前槽點,其他線程不能操做,保證了安全 synchronized (f) { //這裏再次判斷 i 索引位置的數據沒有被修改 //binCount 被賦值的話,說明走到了修改表的過程裏面 if (tabAt(tab, i) == f) { //鏈表 if (fh >= 0) { binCount = 1; for (Node<K,V> e = f;; ++binCount) { K ek; //值有的話,直接返回 if (e.hash == hash && ((ek = e.key) == key || (ek != null && key.equals(ek)))) { oldVal = e.val; if (!onlyIfAbsent) e.val = value; break; } Node<K,V> pred = e; //把新增的元素賦值到鏈表的最後,退出自旋 if ((e = e.next) == null) { pred.next = new Node<K,V>(hash, key, value, null); break; } } } //紅黑樹,這裏沒有使用 TreeNode,使用的是 TreeBin,TreeNode 只是紅黑樹的一個節點 //TreeBin 持有紅黑樹的引用,而且會對其加鎖,保證其操做的線程安全 else if (f instanceof TreeBin) { Node<K,V> p; binCount = 2; //知足if的話,把老的值給oldVal //在putTreeVal方法裏面,在給紅黑樹從新着色旋轉的時候 //會鎖住紅黑樹的根節點 if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key, value)) != null) { oldVal = p.val; if (!onlyIfAbsent) p.val = value; } } } } //binCount不爲空,而且 oldVal 有值的狀況,說明已經新增成功了 if (binCount != 0) { // 鏈表是否須要轉化成紅黑樹 if (binCount >= TREEIFY_THRESHOLD) treeifyBin(tab, i); if (oldVal != null) return oldVal; //這一步幾乎走不到。槽點已經上鎖,只有在紅黑樹或者鏈表新增失敗的時候 //纔會走到這裏,這二者新增都是自旋的,幾乎不會失敗 break; } } } //check 容器是否須要擴容,若是須要去擴容,調用 transfer 方法去擴容 //若是已經在擴容中了,check有無完成 addCount(1L, binCount); return null; }
equals()方法判斷兩個對象是否「相等」。若是不重寫這個方法,equals兩個對象 除非是同一個引用,不然一直不相等(返回false)。
Eclipse默認給咱們重寫的equals()方法,是對象的全部成員變量是否都相等,若是該對象和比較對象的成員變量都相等 則兩個對象互相equals() 也就是相等。
咱們都知道Set集合存放的對象都是不可重複的,Set集合就是根據對象的equals方法判斷對象是否是重複
注意:當此方法被重寫時,一般有必要重寫 hashCode 方法,以維護 hashCode 方法的常規協定,該協定聲明相等對象必須具備相等的哈希碼。
返回該對象的哈希碼值。支持此方法是爲了提升哈希表(例如 java.util.Hashtable
提供的哈希表)的性能。
若是根據 equals(Object) 方法,兩個對象是相等的,那麼對這兩個對象中的每一個對象調用 hashCode
方法都必須生成相同的整數結果。
若是根據 equals(java.lang.Object)
方法,兩個對象不相等,那麼對這兩個對象中的任一對象上調用 hashCode 方法不 要求必定生成不一樣的整數結果。可是,程序員應該意識到,爲不相等的對象生成不一樣整數結果能夠提升哈希表的性能。
——摘自API,你們也就理解了 爲何eclipse中 equals和HasdCode方法給咱們的快捷鍵中,必須一塊兒重寫。
Object
類的 toString
方法返回一個字符串,該字符串由類名(對象是該類的一個實例)、at 標記符「@
」和
此對象哈希碼的無符號十六進制表示組成。換句話說,該方法返回一個字符串,它的值等於
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
以上是JDK默認toString方法的實現和API解釋,可見Object類默認的toString方法和equals方法都和對象的哈希碼有關
重寫toString方法可讓咱們更直觀的理解對象的內容屬性。
反射能夠拿到一個對象的成員變量的值,但方法的參數是出如今方法被調用的時候,
你拿到了class,method,參數類型等這些都沒用,這些都是靜態的,固定的。
也就是說反射拿不到參數的值
StringBuffer表明可變的字符序列,往StringBuffer字符串加東西,直接相加。
String表明不可變字符序列 當咱們執行兩個字符串相加時 須要分配另一塊內存 而後 執行兩次copy。最後把字符串的指針執行新的那塊內存。
StringBuilder和StringBuffer相似 區別是StringBuilder線程非安全。