集合(Collection)
1. 什么是集合?
集合是一組對象組成的一個(gè)整體,又稱為容器,集合類屬于java.util包。集合不同于數(shù)組的地方在于,一是它的容量是可變的,二是集合中只能存儲對象,不能存儲基本數(shù)據(jù)類型
Java的集合類庫有一大一小兩派,一大由Collection接口帶領(lǐng),一小由Map接口帶領(lǐng)。
2. Collection接口
Collection接口下有兩大分支,分別為List接口和Set接口。注意,Collection是接口,而Collections則是java.util包下的一個(gè)具體類。
2.1 List接口
List集合中允許有重復(fù)對象。
2.1.1 ArrayList類
ArrayList分配了一個(gè)動(dòng)態(tài)再分配的對象數(shù)組數(shù)組(說白了就是長度可變的數(shù)組),可以通過索引進(jìn)行隨機(jī)訪問,但是插入刪除比較麻煩,這與數(shù)組的特性是一致的。
List list = new ArrayList();
注:ArrayList是線程不安全的,即它的方法沒有同步;而Vector是線程安全的,它的所有方法都是同步的。
2.1.2 LinkedList類
LinkedList采用鏈表結(jié)構(gòu)保存對象,插入刪除方便,但是訪問慢,這和鏈表的特性是一致的。
List list2 = new LinkedList();

1 import java.util.ArrayList; 2 import java.util.List; 3 4 public class Gather{ 5 public static void main(String[] args) { 6 List list = new ArrayList<>(); 7 for(char ch = 'a'; ch <= 'z'; ch++){ 8 list.add(ch); 9 }10 11 int ran = (int)(Math.random()*(list.size()-1));12 System.out.list.get(ran));13 14 list.remove(2);15 for(int i = 0; i < list.size(); i++){16 System.out.print(list.get(i)+" ");17 }18 }19 }
2.2 Set接口
Set是沒有重復(fù)元素的集合,遍歷Set集合的順序和插入順序并不總是一致,Set集合中的元素可以看作是無序的。
2.2.1 HashSet類
HashSet基于散列表
舉例:

1 public class People { 2 private String name; 3 private long id_card; 4 public People(String name, long id_card){ 5 this.name = name; 6 this.id_card = id_card; 7 } 8 9 public long getId_card(){10 return id_card;11 }12 13 public void setId_card(long id_card){14 this.id_card = id_card;15 }16 17 public String getName(){18 return name;19 }20 21 public void setName(String name){22 this.name = name;23 }24 }25 ——————————華麗的分割線————————————26 import java.util.HashSet;27 import java.util.Iterator;28 import java.util.Set;29 30 public class CollectionDemo {31 32 public static void main(String[] args) {33 Set<People> hashSet = new HashSet<People >();34 hashSet.add(new People("張三", 2000));35 hashSet.add(new People("李四", 2001));36 hashSet.add(new People("王五", 2002));37 38 Iterator<People> it = hashSet.iterator();39 System.out.println("集合中的元素是:");40 while(it.hasNext()){41 People person = it.next();42 System.out.println(person.getName()+" "+person.getId_card());43 }44 }45 }
2.2.2 TreeSet類
TreeSet樹集是一個(gè)有序集合,可以以任意順序?qū)⒃夭迦氲郊现小1闅v時(shí),按照排序后的順序呈現(xiàn),排序是用紅黑樹完成的。
TreeSet如何知道元素的大小呢,在默認(rèn)情況下,TreeSet假定插入的元素實(shí)現(xiàn)了Comparable接口。這個(gè)接口定義了一個(gè)方法:
Public interface Comparable<T>{
Int compareTo(T other);
}
通過Comparable接口定義排列順序有局限性。對于一個(gè)給定的類,只能實(shí)現(xiàn)這個(gè)接口一次,如果想要使用不同規(guī)則,多次對類對象進(jìn)行排序,就要用到Comparator對象傳遞給TreeSet構(gòu)造器來定義排序規(guī)則。Comparator接口聲明了一個(gè)帶有兩個(gè)顯式參數(shù)的compare方法:
Public interface Comparator<T>{
Int compare(T a, T b);
}
與compareTo方法一樣,如果a位于b之前compare方法則返回負(fù)值,相等返回0,否則返回正值。
如果按照描述信息進(jìn)行排序,就直接定義一個(gè)實(shí)現(xiàn)Comparator接口的類:
Class ItemComparator implements Comparator<Item>{
Public int compare(Item a, Item b){
String descrA = a.getDescription();
String descrB = b.getDescription();
Return descrA.compareTo(descrB);
}
}
然后將這個(gè)類的對象傳遞給樹集的構(gòu)造器:
ItemComparator comp = new ItemComparator();
SortedSet<Item> sortByDescrition = new TreeSet<>(comp);
(總是就是,在構(gòu)造TreeSet時(shí),傳給它一個(gè)對象參數(shù),這個(gè)對象是實(shí)現(xiàn)了Comparator接口的類的一個(gè)實(shí)例,它定義了一種比較TreeSet集中元素的規(guī)則,就醬紫(⊙o⊙)哦)
注:在Java中,散列表用鏈表數(shù)組實(shí)現(xiàn),每個(gè)鏈表被稱為桶(bucket)。要想查找表中對象的位置,就要先計(jì)算它的散列碼(也就是哈希碼hashCode),然后與桶的總數(shù)取余,所得到的結(jié)果就是保存這個(gè)元素的桶的索引。例如,散列碼76268,并且有128個(gè)桶,則對象應(yīng)該保存在第108號桶中。
桶數(shù)是指用于收集具有相同散列值的桶的數(shù)目。標(biāo)準(zhǔn)類庫使用的桶數(shù)是2的冪,默認(rèn)值為16(為表大小提供的任何值都將被自動(dòng)轉(zhuǎn)換為2的下一個(gè)冪)。
散列表可以用于實(shí)現(xiàn)幾個(gè)重要的數(shù)據(jù)結(jié)構(gòu),其中最簡單的就是set類型。Set的add方法首先在集中查找要添加的對象,如果不存在,就將這個(gè)對象添加進(jìn)去。
3.Map接口
Map提供了將鍵值映射到值的對象,鍵不能重復(fù),一個(gè)鍵映射到一個(gè)值。
3.1 HashMap類
HashMap也叫散列映射表,它對鍵進(jìn)行散列,散列或比較函數(shù)只能作用于鍵,與鍵關(guān)聯(lián)的值不能進(jìn)行散列或比較。
HashMap是基于哈希表的Map接口的實(shí)現(xiàn),增刪的效率更高。允許null值和null鍵。
3.2 TreeMap類
TreeMap也叫樹映射表,用鍵的整體順序?qū)υ剡M(jìn)行排序。
TreeMap類不僅實(shí)現(xiàn)了Map類,還實(shí)現(xiàn)了java.util.SortedMap接口,因此集合中元素具有一定的順序。增刪效率比HashMap差。由于映射關(guān)系是根據(jù)鍵對象按照一定的順序排列的,所以不允許鍵值為null

1 public class Emp { 2 private String e_id; 3 private String e_name; 4 public Emp(String e_id,String e_name){ 5 this.e_id = e_id; 6 this.e_name = e_name; 7 } 8 public String getE_id() { 9 return e_id;10 }11 public void setE_id(String e_id) {12 this.e_id = e_id;13 }14 public String getE_name() {15 return e_name;16 }17 public void setE_name(String e_name) {18 this.e_name = e_name;19 }20 }21 —————————華麗的分割線———————————22 import java.util.HashMap;23 import java.util.Iterator;24 import java.util.Map;25 import java.util.Set;26 import java.util.TreeMap;27 28 public class MapText {29 public static void main(String[] args) {30 Map map = new HashMap();31 Emp emp = new Emp("001","zhangsan");32 Emp emp2 = new Emp("015","lisi");33 Emp emp3 = new Emp("009","wangyi");34 Emp emp4 = new Emp("011","tangbao");35 map.put(emp.getE_id(), emp.getE_name());36 map.put(emp2.getE_id(),emp2.getE_name());37 map.put(emp3.getE_id(), emp3.getE_name());38 map.put(emp4.getE_id(), emp4.getE_name());39 40 Set set = map.keySet();41 Iterator it = set.iterator();42 //HashMap的無序是指既不是按照添加順序,也不是按照鍵值大小順序43 /*HashMap中哈希碼的定義44 * public final int hashCode() {45 return Objects.hashCode(key) ^ Objects.hashCode(value);46 }47 *Objects類中哈希碼的定義(Objects繼承自O(shè)bject)48 *public static int hashCode(Object o) {49 return o != null ? o.hashCode() : 0;50 }51 */52 System.out.println("HashMap類實(shí)現(xiàn)的Map集合,無序:");53 while(it.hasNext()){54 String str = (String)it.next();55 String name = (String)map.get(str);56 System.out.println(str+":"+name);57 }58 59 TreeMap treemap = new TreeMap();60 treemap.putAll(map);61 Iterator it2 = treemap.keySet().iterator();62 System.out.println("TreeMap 類實(shí)現(xiàn)的Map集合,鍵對象升序:");63 while(it2.hasNext()){64 String str = (String)it2.next();65 String name = (String)map.get(str);66 System.out.println(str+""+name);67 }68 }69 }
3.3其它
集合框架并沒有將映射表視為一個(gè)集合,但是可以獲得映射表的視圖,這時(shí)一組實(shí)現(xiàn)了Collection接口的對象,或者它的子接口的視圖。
有3個(gè)視圖,分別是:鍵集、值集合(不是集)和鍵/值對集。鍵與鍵/值對形成了一個(gè)集,這是因?yàn)樵谟成浔碇幸粋€(gè)鍵只能有一個(gè)副本。
Set<K> keySet()
Collection<K> values()
Set<Map.Entry<K,V>> entrySet()
注意:keySet既不是HashSet,也不是TreeSet,而是實(shí)現(xiàn)了Set接口的某個(gè)其他類的對象。Set接口擴(kuò)展了Collection接口。
4.Iterator接口
通過迭代器Iterator接口可以遍歷集合。
Iterator接口位于java.util包下,它有3個(gè)方法:
hasNext(): 如果還有元素可迭代,返回true
next(): 返回迭代的下一個(gè)元素
remove(): 刪除上次調(diào)用next()方法時(shí)返回的元素(注意:對next()和remove()方法的調(diào)用具有相互依賴性,調(diào)用remove()之前沒有調(diào)用next()是不合法的。如果想要?jiǎng)h除后面的元素,必須通過調(diào)用next()越過前面的元素才行)
反復(fù)調(diào)用next()方法可以遍歷集合,但是當(dāng)?shù)竭_(dá)了集合末尾,會拋出NoSuchElementException。

1 Collection<String> c = ...; 2 Iterator<String> iter = c.iterator(); 3 while(iter.hasNext()){ 4 String element = iter.next(); 5 Do sth with element 6 } 7 //從Java SE 5.0 起,可以用for each循環(huán)來遍歷 8 for(String element : c){ 9 Do sth with element10 }
4.1迭代順序
元素被訪問的順序取決于集合類型,如果對ArrayList進(jìn)行迭代,從索引為0的位置開始,沒迭代一次,索引加1。如果訪問的是HashSet,元素將按隨機(jī)順序出現(xiàn),雖然可以保證遍歷,但無法預(yù)知訪問次序。
4.2 ListIterator接口

1 import java.util.ArrayList; 2 import java.util.Collections; 3 import java.util.Iterator; 4 import java.util.ListIterator; 5 6 public class ListIteratorDemo { 7 public static void main(String[] args) { 8 ArrayList<Integer> array = new ArrayList<>(); 9 Collections.addAll(array, 1,2,3,4,5,6);10 System.out.println("集合中的元素:"+array);11 ListIterator<Integer> iterator = array.listIterator();12 13 boolean hasNext = iterator.hasNext();14 System.out.println("集合是否還有下一個(gè)元素:"+hasNext);15 16 boolean hasprevious = iterator.hasPrevious();17 System.out.println("集合是否還有前一個(gè)元素:"+hasPrevious);18 System.out.println("nextIndex:"+iterator.nextIndex());19 System.out.println("next:"+iterator.next());20 System.out.println("nextIndex:"+iterator.nextIndex());21 System.out.println("next:"+iterator.next());22 System.out.println("previousIndex:"+iterator.previousIndex());23 System.out.println("previous:"+iterator.previous());24 25 System.out.println("nextIndex:"+iterator.nextIndex());26 System.out.println("next:"+iterator.next());27 28 //add將元素插入到nextIndex所指的位置29 System.out.println("nextIndex:"+iterator.nextIndex());30 iterator.add(999);31 System.out.println("向集合中添加999后:"+array);32 33 //set將next()返回的元素替換為10034 iterator.next();35 iterator.set(100);36 System.out.println("集合中的元素:"+array);37 38 //remove將100刪除39 iterator.remove();40 System.out.println("集合中的元素:"+array); 41 }42 }
5.Deque接口
Java SE 6中引入了Deque接口,并由ArrayDeque和LinkedList類實(shí)現(xiàn)。這兩個(gè)類都提供了雙端隊(duì)列。在必要時(shí)可增加隊(duì)列長度。
public interface Deque<E> extends Queue<E>
6.集合框架
框架(framework)是一個(gè)類的集,它奠定了創(chuàng)建高級功能的基礎(chǔ)。框架包含很多超類,這些超類擁有非常有用的功能、策略和機(jī)制。框架使用者創(chuàng)建的子類可以擴(kuò)展超類的功能,而不必重新創(chuàng)建這些基本的機(jī)制。例如,Swing就是一種用戶界面的機(jī)制。

新聞熱點(diǎn)
疑難解答
圖片精選