一、集合的由來
通常,我們的程序需要根據程序運行時才知道創建多少個對象。但若非程序運行,程序開發階段,我們根本不知道到底需要多少個數量的對象,甚至不知道它的准確類型。為了滿足這些常規的編程需要,我們要求能在任何時候,任何地點創建任意數量的對象,而這些對象用什么來容納呢?我們首先想到了數組,但是數組只能放統一類型的數據,而且其長度是固定的,那怎么辦呢?集合便應運而生了!
為了對集合有個更加深入的了解,可以看我的這一篇文章:用 Java 數組來實現 ArrayList 集合 http://www.cnblogs.com/ysocean/p/6812674.html
二、集合是什么?
Java集合類存放於 java.util 包中,是一個用來存放對象的容器。
注意:①、集合只能存放對象。比如你存一個 int 型數據 1放入集合中,其實它是自動轉換成 Integer 類后存入的,Java中每一種基本類型都有對應的引用類型。
②、集合存放的是多個對象的引用,對象本身還是放在堆內存中。
③、集合可以存放不同類型,不限數量的數據類型。
三、Java 集合框架圖
此圖來源於:http://blog.csdn.net/u010887744/article/details/50575735
大圖可以點此訪問:http://img.blog.csdn.net/20160124221843905
發現一個特點,上述所有的集合類,除了 map 系列的集合,即左邊集合都實現了 Iterator 接口,這是一個用於遍歷集合中元素的接口,主要hashNext(),next(),remove()三種方法。它的一個子接口 ListIterator 在它的基礎上又添加了三種方法,分別是 add(),previous(),hasPrevious()。也就是說如果實現 Iterator 接口,那么在遍歷集合中元素的時候,只能往后遍歷,被遍歷后的元素不會再被遍歷到,通常無序集合實現的都是這個接口,比如HashSet;而那些元素有序的集合,實現的一般都是 LinkedIterator接口,實現這個接口的集合可以雙向遍歷,既可以通過next()訪問下一個元素,又可以通過previous()訪問前一個 元素,比如ArrayList。
還有一個特點就是抽象類的使用。如果要自己實現一個集合類,去實現那些抽象的接口會非常麻煩,工作量很大。這個時候就可以使用抽象類,這些抽象類中給我們提供了許多
現成的實現,我們只需要根據自己的需求重寫一些方法或者添加一些方法就可以實現自己需要的集合類,工作量大大降低。
四、集合詳解
①、Iterator:迭代器,它是Java集合的頂層接口(不包括 map 系列的集合,Map接口 是 map 系列集合的頂層接口)
Object next():返回迭代器剛越過的元素的引用,返回值是 Object,需要強制轉換成自己需要的類型
boolean hasNext():判斷容器內是否還有可供訪問的元素
void remove():刪除迭代器剛越過的元素
所以除了 map 系列的集合,我們都能通過迭代器來對集合中的元素進行遍歷。
注意:我們可以在源碼中追溯到集合的頂層接口,比如 Collection 接口,可以看到它繼承的是類 Iterable
那這就得說明一下 Iterator 和 Iterable 的區別:
Iterable :存在於 java.lang 包中。
我們可以看到,里面封裝了 Iterator 接口。所以只要實現了只要實現了Iterable接口的類,就可以使用Iterator迭代器了。
Iterator :存在於 java.util 包中。核心的方法next(),hasnext(),remove()。
這里我們引用一個Iterator 的實現類 ArrayList 來看一下迭代器的使用:暫時先不管 List 集合是什么,只需要看看迭代器的用法就行了
1 //產生一個 List 集合,典型實現為 ArrayList。 2 List list = new ArrayList(); 3 //添加三個元素 4 list.add("Tom"); 5 list.add("Bob"); 6 list.add("Marry"); 7 //構造 List 的迭代器 8 Iterator it = list.iterator(); 9 //通過迭代器遍歷元素 10 while(it.hasNext()){ 11 Object obj = it.next(); 12 System.out.println(obj); 13 }
②、Collection:List 接口和 Set 接口的父接口
1 //我們這里將 ArrayList集合作為 Collection 的實現類 2 Collection collection = new ArrayList(); 3 4 //添加元素 5 collection.add("Tom"); 6 collection.add("Bob"); 7 8 //刪除指定元素 9 collection.remove("Tom"); 10 11 //刪除所有元素 12 Collection c = new ArrayList(); 13 c.add("Bob"); 14 collection.removeAll(c); 15 16 //檢測是否存在某個元素 17 collection.contains("Tom"); 18 19 //判斷是否為空 20 collection.isEmpty(); 21 22 //利用增強for循環遍歷集合 23 for(Object obj : collection){ 24 System.out.println(obj); 25 } 26 //利用迭代器 Iterator 27 Iterator iterator = collection.iterator(); 28 while(iterator.hasNext()){ 29 Object obj = iterator.next(); 30 System.out.println(obj); 31 }
③、List :有序,可以重復的集合。
由於 List 接口是繼承於 Collection 接口,所以基本的方法如上所示。
1、List 接口的三個典型實現:
①、List list1 = new ArrayList();
底層數據結構是數組,查詢快,增刪慢;線程不安全,效率高
②、List list2 = new Vector();
底層數據結構是數組,查詢快,增刪慢;線程安全,效率低,幾乎已經淘汰了這個集合
③、List list3 = new LinkedList();
底層數據結構是鏈表,查詢慢,增刪快;線程不安全,效率高
怎么記呢?我們可以想象:
數組就像身上編了號站成一排的人,要找第10個人很容易,根據人身上的編號很快就能找到。但插入、刪除慢,要望某個位置插入或刪除一個人時,后面的人身上的編號都要變。當然,加入或刪除的人始終末尾的也快。
鏈表就像手牽着手站成一圈的人,要找第10個人不容易,必須從第一個人一個個數過去。但插入、刪除快。插入時只要解開兩個人的手,並重新牽上新加進來的人的手就可以。刪除一樣的道理。
2、除此之外,List 接口遍歷還可以使用普通 for 循環進行遍歷,指定位置添加元素,替換元素等等。
1 //產生一個 List 集合,典型實現為 ArrayList 2 List list = new ArrayList(); 3 //添加三個元素 4 list.add("Tom"); 5 list.add("Bob"); 6 list.add("Marry"); 7 //構造 List 的迭代器 8 Iterator it = list.iterator(); 9 //通過迭代器遍歷元素 10 while(it.hasNext()){ 11 Object obj = it.next(); 12 //System.out.println(obj); 13 } 14 15 //在指定地方添加元素 16 list.add(2, 0); 17 18 //在指定地方替換元素 19 list.set(2, 1); 20 21 //獲得指定對象的索引 22 int i=list.indexOf(1); 23 System.out.println("索引為:"+i); 24 25 //遍歷:普通for循環 26 for(int j=0;j<list.size();j++){ 27 System.out.println(list.get(j)); 28 }
④、Set:典型實現 HashSet()是一個無序,不可重復的集合
1、Set hashSet = new HashSet();
①、HashSet:不能保證元素的順序;不可重復;不是線程安全的;集合元素可以為 NULL;
②、其底層其實是一個數組,存在的意義是加快查詢速度。我們知道在一般的數組中,元素在數組中的索引位置是隨機的,元素的取值和元素的位置之間不存在確定的關系,因此,在數組中查找特定的值時,需要把查找值和一系列的元素進行比較,此時的查詢效率依賴於查找過程中比較的次數。而 HashSet 集合底層數組的索引和值有一個確定的關系:index=hash(value),那么只需要調用這個公式,就能快速的找到元素或者索引。

Set treeSet = new TreeSet(); treeSet.add(1); //添加一個 Integer 類型的數據 treeSet.add("a"); //添加一個 String 類型的數據 System.out.println(treeSet); //會報類型轉換異常的錯誤
* 自動排序:添加自定義對象的時候,必須要實現 Comparable 接口,並要覆蓋 compareTo(Object obj) 方法來自定義比較規則
如果 this > obj,返回正數 1
如果 this < obj,返回負數 -1
如果 this = obj,返回 0 ,則認為這兩個對象相等

public class TreeSetTest { public static void main(String[] args) { Person p1 = new Person(1); Person p2 = new Person(2); Person p3 = new Person(3); Set<Person> set = new TreeSet<>(new Person()); set.add(p1); set.add(p2); set.add(p3); System.out.println(set); //結果為[1, 2, 3] } } class Person implements Comparator<Person>{ public int age; public Person(){} public Person(int age){ this.age = age; } @Override /*** * 根據年齡大小進行排序 */ public int compare(Person o1, Person o2) { // TODO Auto-generated method stub if(o1.age > o2.age){ return 1; }else if(o1.age < o2.age){ return -1; }else{ return 0; } } @Override public String toString() { // TODO Auto-generated method stub return ""+this.age; } }
⑤、Map:key-value 的鍵值對,key 不允許重復,value 可以
1、嚴格來說 Map 並不是一個集合,而是兩個集合之間 的映射關系。
2、這兩個集合沒每一條數據通過映射關系,我們可以看成是一條數據。即 Entry(key,value)。Map 可以看成是由多個 Entry 組成。
3、因為 Map 集合即沒有實現於 Collection 接口,也沒有實現 Iterable 接口,所以不能對 Map 集合進行 for-each 遍歷。
Map<String,Object> hashMap = new HashMap<>(); //添加元素到 Map 中 hashMap.put("key1", "value1"); hashMap.put("key2", "value2"); hashMap.put("key3", "value3"); hashMap.put("key4", "value4"); hashMap.put("key5", "value5"); //刪除 Map 中的元素,通過 key 的值 hashMap.remove("key1"); //通過 get(key) 得到 Map 中的value Object str1 = hashMap.get("key1"); //可以通過 添加 方法來修改 Map 中的元素 hashMap.put("key2", "修改 key2 的 Value"); //通過 map.values() 方法得到 Map 中的 value 集合 Collection<Object> value = hashMap.values(); for(Object obj : value){ //System.out.println(obj); } //通過 map.keySet() 得到 Map 的key 的集合,然后 通過 get(key) 得到 Value Set<String> set = hashMap.keySet(); for(String str : set){ Object obj = hashMap.get(str); //System.out.println(str+"="+obj); } //通過 Map.entrySet() 得到 Map 的 Entry集合,然后遍歷 Set<Map.Entry<String, Object>> entrys = hashMap.entrySet(); for(Map.Entry<String, Object> entry: entrys){ String key = entry.getKey(); Object value2 = entry.getValue(); System.out.println(key+"="+value2); } System.out.println(hashMap);
Map 的常用實現類:
⑥、Map 和 Set 集合的關系
1、都有幾個類型的集合。HashMap 和 HashSet ,都采 哈希表算法;TreeMap 和 TreeSet 都采用 紅-黑樹算法;LinkedHashMap 和 LinkedHashSet 都采用 哈希表算法和紅-黑樹算法。
2、分析 Set 的底層源碼,我們可以看到,Set 集合 就是 由 Map 集合的 Key 組成。