集合繼承體系圖的理解


       

一、Collection、Collections的區別?

  1. java.util.Collection是一個集合的頂級接口。它提供了對集合對象進行基本操作的通用接口方法。Collection接口在Java類庫中有很多具體的實現,其直接繼承接口有List與Set。

  2. Collections是集合類的一個工具類,其中提供了一系列靜態方法,用於對集合中元素進行排序、搜索以及線程安全等操作。

    1)排序(sort):使用sort方法可以根據元素的自然順序對指定列表按升序進行排序。列表中的所有元素都必須實現Comparable接口。此列表內的所有元素都必須是使用指定比較器可相互比較的。

 1 List<Integer> list = new ArrayList<Integer>();  2         int array[] = {112, 111, 23, 456, 231 };  3         for (int i = 0; i < array.length; i++) {  4  list.add(array[i]);  5  }  6  Collections.sort(list);  7         for (int i = 0; i < array.length; i++) {  8  System.out.println(list.get(i));  9  } 10 結果:23  111  112  231  456

    2)混排(shuffling):混排算法所做的正好與sort相反,它打亂在一個List中可能有的任何排列的蹤跡。也就是說,基於隨機源的輸入重排該list,這樣的排列具有相同的可能性(假設隨機源是公正的)。這個算法在實現一個碰運氣的游戲中是非常有用的。例如,它可被用來混派代表一副牌的card對象的一個list。另外,在生成測試案例時,它也是十分有用的。

    3)反轉(reverse):使用reverse方法可以根據元素的自然順序對指定列表按降序進行排序。Collections.reverse(list)

    4)替換所有的元素(fill):使用指定元素替換指定列表中的所有元素。Collections.fill(li,"aaa");

    5)拷貝(copy):用兩個參數,一個目標list和一個源list,將源的元素拷貝到目標,並覆蓋它的內容。目標list至少與源一樣長。如果它更長,則在目標list中的剩余元素不受影響。

      Collections.copy(list,li):前面一個參數是目標列表,后一個是源列表

    6)返回Collections中的最小元素(min):根據指定比較器產生的順序,返回給定collection的最小元素。collection中的所有元素都必須是通過指定比較器可相互比較的。

      Collections.min(list)

    7)返回Collections中的最大元素(max):根據指定比較器產生的順序,返回給頂collection的最大元素。Collections.max(list)

    8)lastIndexOfSubList:返回值定源列表中最后一次出現指定目標列表的起始位置。 int count = Collections.lastIndexOfSubList(list,li);

    9)Rotate:根據指定的距離循環移動指定列表中的元素。  Collections.rotate(list,-1); //如果是負數,則正向移動,正數則反向移動。

二、List、Set的區別?

List與Set都繼承於Collection,Collection是集合的頂級接口;

  List為有序可重復的集合接口,ArrayList、LinkedList、Vector為其實現類;

  Set是無序不重復的集合接口,HashSet、LinkedHashSet、TreeSet為其實現類。

    取出元素的方法只有迭代器。不可以存放重復元素,元素存取是無序的。因此存入Set中的每個對象都必須重寫equals()和hashCode()方法來確保對象的唯一性。

三、ArrayList、LinkedList、Vector的區別和實現原理?

  ArrayList和Vector只能按順序存儲元素(從下標為0的位置開始),刪除元素的時候,需要移位並置空,默認初始化容量都是10。

  ArrayList和Vector基於數組實現的,LinkedList基於雙向循環鏈表實現的(含有頭結點)。

1、線程安全性

  ArrayList不具有線程安全性,用在單線程環境中。LinkedList也是線程不安全的,如果在並發環境下使用它們,可以用Colletions類中的靜態方法synchronizedList()對ArrayList和LinkedList進行調用即可。

  Vector是線程安全的,即它的大部分方法都包含關鍵字synchronized。Vector的效率沒有ArrayList和LinkedList高。

2、擴容機制

  從內部實現機制來講,ArrayList和Vector都是使用Object的數組形式來存儲的。當你向這兩種類型中增加元素的時候,若容量不夠,需要進行擴容。ArrayList擴容后的容量是之前的1.5倍,然后,把之前的數據拷貝到新建的數組。Vector默認情況下擴容后的容量是之前的2倍。

  Vector可以設置容量增量,而ArrayList不可以。在Vector中有capacityIncrement:向量的大小大於其容量時,容量自動增加的量。如果在創建Vector時,指定了capacityIncrement的大小;則每次當Vector中動態數組容量需要增加時,如果容量的增量大於零,增加的大小都是capacityIncrement。如果容量的增量小於等於零,則每次需要增大容量時,向量的容量將增大為之前的2倍。

  可變長度數組的原理:當元素個數超過數組的長度時,會產生一個新數組,將原數組的數據復制到新數組,再將新的元素添加到新數組中。

3、增刪改查的效率

  ArrayList和Vector中,從指定的位置(用index)檢索一個對象,或在集合的末尾插入、刪除一個對象的時間是一樣的,可表示為O(1)。但是,如果在集合的其他位置增加或刪除元素那么花費的時間是O(N)。LinkedList中,在插入、刪除集合中任何位置的元素所花費的時間都是一樣的—O(1)。但它在索引一個元素的時候比較慢,為O(N)。

  所以,如果只是查找特定位置的元素或只在集合的末端增加、移除元素,那么使用Vector或ArrayList都可以。如果是對其他指定位置的插入、刪除操作,最好選擇LinkedList。

四、HashMap、HashTable

  1、HashTable是線程安全的,方法是synchronized的,適合在多線程環境中使用,效率稍低;HashMap是線程不安全的,方法不是synchronized的,效率稍高,適合在單線程環境下使用,所以在多線程場合下使用的話,需要手動同步HashMap,Collections.sychronizedMap()。

  HashTable的效率比較低的原因?

    在線程競爭激烈的情況下HashTable的效率非常低下。因為當一個線程訪問HashTable的同步方法時,訪問其他同步方法的線程就可能進入阻塞或者輪詢狀態。如線程1使用PUT進行添加元素,線程2不但不能使用PUT方法添加元素,並且也不能使用GET方法來獲取元素,所以競爭越激烈效率越低。

  2、HashMap的key和value都可以為null值,HashTable的key和value都不允許有null值。

  3、HashMap中的數組的默認大小是16,而且一定是2的倍數,擴容后的數組長度是之前數組長度的2倍。HashTable中數組的默認大小為11,擴容后數組長度是之前數組長度的2倍+1。

  4、哈希值的使用不同。

    HashMap重新計算hash值,而且用&代替求模:

 1 int hash = hash(key.hashcode());  2 int i = indexFor(hash,table.length);  3 static int hash(Object x){  4     int h = x.hashCode();  5     h+=~(h<<9);  6     h^=(h>>>14);  7     h+=(h<<4);  8     h^=(h>>>10);  9     return h; 10 } 11 static int indexFor(int h,int length){ 12     return h&(length-1);//hashmap的表長永遠是2^n
13 }

    HashTable直接使用對象的hashCode值:

1 int hash = key.hashCode(); 2 int index = (hash&&0x7FFFFFFF)

  5、判斷是否含有某個鍵

  在HashMap中,null可以作為鍵,這樣的鍵只有一個;可以有一個或多個鍵所對應的值為null。當get()方法返回null值時,既可以表示HashMap中沒有該鍵,也可以表示該鍵所對應的值為null。因此,在HashMap中不能用get()方法來判斷HashMap中是否存在某個鍵,而應該用ContainsKey()方法來判斷。Hashtable的鍵值都不能為null,所以可以用get()方法來判斷是否含有某個鍵。

五、HashSet

  哈希表存放的是哈希值。hashset存儲元素的順序並不是按照存入時的順序(和list顯然不同)而是按照哈希值來存的所以取數也是按照哈希值取得。元素的哈希值是通過元素的hashcode方法來獲取的,hashset首先判斷兩個元素的哈希值,如果哈希值一樣,接着會比較equals方法,如果equals結果為true,hashset就視為同一個元素。如果equals為false就不是同一個元素。

  哈希值相同equals為false的元素是怎么存儲呢?就是在同樣的哈希值下順延(可以認為哈希值相同的元素放在一個哈希桶中),也就是哈希一樣的存一列。

六、TreeSet

  1、treeset是使用二叉樹的原理對add的對象按照指定的順序排序,每增加一個對象都會進行排序,將對象插入到二叉樹指定的位置;

  2、Integer和String對象都可以進行默認的treeset排序,而自定義的對象是不可以的,自己定義的類必須實現Comparable接口,並且覆蓋相應的compareTo()函數,才可以正常使用。

  3、在重寫compareTo()函數時,要返回相應的值才能使treeset按照一定的規則進行排序。

  4、比較此對象與指定對象順序,如果該對象小於、等於或大與指定對象,則分別返回負整數、零或正整數。

七、TreeMap(可排序)

  treeMap實現SortedMap接口,能夠把它保存的記錄根據鍵排序,默認是按鍵值的升序排序,也可以指定排序的比較器,當用iterator遍歷treeMap時,得到的記錄是排過序的。

  如果使用排序的映射,建議使用treeMap。

  在使用treeMap時,key必須實現Comparable接口或在構造treeMap傳入自定義的Comparator,否則會在運行時拋出java.lang.ClassCastException類型的異常。

八、LinkedHashMap(記錄插入順序)

  LinkedHashMap是hashMap的一個子類,保存了記錄的插入順序,在用iterator遍歷LinkedHashMap時,先得到的記錄肯定是先插入的,也可以在構造函數時帶參數,按照訪問次序排序。

九、Map接口與Collection接口的區別?

  Map是雙列的,Collection是單列的;

  Map的鍵值唯一,Collection的子接口set是唯一的;

  Map的數據結構只針對鍵有效,Collection針對元素有效;

集合 初始容量 擴容因子 負載因子 底層結構 線程是否安全
ArrayList 10 1.5 無(滿了擴容) 數組
Vector 10 2 無(滿了擴容) 數組
HashMap 16 2 0.75 數組+鏈表+紅黑樹
HashSet 16 2 0.75 數組+鏈表+紅黑樹
HashTable 11 2*1+1 0.75 數組+鏈表

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM