一、java集合類基本概念
有時我們需要集中存放多個資料,一般情況下,陣列就是一個很好的選擇,前提是我們事先已經明確知道我們將要儲存的物件的數量。一旦在陣列初始化時指定了這個陣列長度。這樣陣列長度就不可變了,如果我們想要儲存一個可以動態增長的資料,java集合類就是一個很好的設計方案。
集合類主要負責儲存其他資料,所以集合類一般也被成為容器類。所以的集合類都位於java.util包下。
- Collection
一組服從某種規則的元素 1.1) List必須保持元素特定的順序 1.2) Set不能有重複元素 1.3) Queue保持一個佇列(先進先出)的順序 2) Map
一組成對的"鍵值對"物件
Collection 和Map的區別在於容器中每個位置儲存元素的個數
(1)Collection 每個位置只能儲存一個元素 (2)Map 儲存的是“鍵值對”,就像一個小型資料庫。我們可以通過鍵找到對應的值
二、Java集合類架構層次關係
1.Iterface Iterable
迭代器介面,這是Collection類的父介面。實現這個Iterable介面的物件允許使用foreach進行遍歷,也就是說,所有的Collection集合物件都具有“foreach可遍歷性”。這個Iterable介面只有一個方法:iterator()。他返回一個代表當前集合物件的泛型迭代器,用於之後的遍歷操作。
1.1 Collection
Collection 是最基本的集合介面,一個Collection代表一組Object的集合,這些Object被稱作Collection的元素。Collection是一個介面,用以提供規範定義,不能被例項化使用
1)Set
Set集合類似於一個桶,放進Set集合裡的多個物件之間沒有明顯的順序。Set繼承自Collection介面,不能包含有重複元素。
Set判斷兩個物件相同不是使用”==“運算子,而是根據equals方法。也就是說,我們在加入一個新元素時,如果這個新元素物件和Set中已有對你好進行注意equals比較都返回false,則Ser就會接受這個新元素物件,否則拒絕。
因為Set的這個制約,在使用Set集合時,應該注意兩點:1是Set集合裡的元素的實現類實現一個有效的equals(Object)方法 2對Set的建構函式,傳入的Collection引數不能包含重複的元素
1.1)HashSet
HastSet是Set介面的典型實現,HashSet使用HASH演算法來儲存集合中的元素,因此具有良好的存取和查詢效能。當向HashSet集合中存入一個元素時,HashSet會呼叫該物件的hashCode()方法來得到該物件的hashCode值,然後根據該HashCode值決定該物件在HashSet的儲存位置。
1.1.1)LinkedHashSet
LinkedHashSet集合也是根據元素的hashCode值來決定元素的儲存位置,但和HashSet不同是,它同時使用連結串列維護元素的次序,這樣使得元素看起來是以插入的順序儲存。
當遍歷LinkedHashSet集合裡的元素是,LinkedHashSet將會按元素的新增順序來訪問集合裡的元素。
LinkedHashSet需要維護元素的插入順序,因此效能略低於HashSet的效能,但在迭代訪問Set全部元素時,將會有很好的效能。
1.2)SortedSet
此介面主要用於排序操作,即實現此介面的子類都屬於排序的子類
1.2.1)TreeSet
TreeSet是Sorted介面的實現類,TreeSet可以確保集合元素屬於排序狀態
1.3)EnumSet
EnumSet是一個專門為美劇類設計的集合類,EnumSet中所有元素都必須是指定悲劇型別的的列舉值,該列舉型別在建立Enumset時顯示或隱式的指定。EnumSet的集合元素也是有序的。
2)List
List集合代表一個元素有序,可重複的集合,集合中每個元素都有其對應的順序索引。List集合允許加入重複元素,因為他可以通過索引來訪問指位置的集合元素,list集合預設按元素的新增順序設定元素的索引
2.1)ArrayList
ArrayList是基於陣列實現的List類,他封裝了一個動態的增長的,允許再分配的Object[]陣列。
2.2)Vector
Vector和ArrayList在用法上幾乎完全相同,但由於Vector是一個古老的集合,所以Vector提供一些方法名很長的方法,之後將Vector改為實現List介面,統一歸入集合框架體系銅
2.2.1)Stack
Stack是Vector提供的一個子類,用於模擬棧這種資料結構
2.3)LinkedList
implement List,Deque。實現List介面,能對他進行佇列操作,即可以根據索引來隨機訪問集合中元素。同時他還實現Deque介面,即能將LinkedList當做雙端佇列使用。自然也可以被當做“棧來使用”。
1.2Map
Map用於儲存具有“對映關係”資料,因此Map集合裡儲存著兩組值,一組值用於儲存Map裡的key,另外一組值用於儲存Map裡的value。key和value都可以是任何引用型別的資料。Map的key不允許重複,即同一個Map物件的任何兩個Key通過equals方法比較結果總是返回false;
Map的這些實現類和子介面中key集的儲存形式和Set集合完全相同(即key不能重複)
Map的這些實現類和子介面中value集的儲存形式和List非常類似(即value可以重複,根據索引來查詢)
1)HashMap
和HashSet不能保證元素的順序一樣,HashMap也不能保證key-value對的順序。並且類似於HashSet判斷兩個key是否相等的標準也是:兩個key通過equals()方法比較返回true。
同時兩個key的hashCode值也必須相等。
1.1)LinkedHashMap
LinkedHashMap也使用雙向連結串列來維護key-value對的順序,與key-value對的插入順序一致(注意和TreeMap對所有的key-value進行排序進行區份)
2)HashTable
2.1)properties
3)sortedMap
正如Ser介面派生出SortedSet子介面,SortedSet介面有一個TreeSet實現類一樣,Map介面也派生出一個SortedMap實現類
3.1)TreeMap
TreeMap就是一個紅黑樹資料結構,每一個key-value對即作為紅黑樹一個節點。TreeMap儲存key-value對(節點)時,需要根據key對及誒單進行排序。TreeMap可以包含保證所有的key-value對都處於有序狀態。同樣,TreeMap也有兩種排序方式:自然排序,定製排序
3.Java集合類的Demo
1.Set
HashSet
import java.util.*
//類A的equals()方法總是返回true,但沒有重寫其hashCode()方法。不能保證當前物件是HashSet的唯一物件
class A { public bollean equals(Object obj) { return true;
} } //類B的hashCode()方法總是返回true,但沒有重寫其equals()方法。不能保證當前物件是HashSet的唯一物件 class B { public bollean hashCode(Object obj) { return 1;
} } //類C的hashCode()方法總是返回2,且有重寫其equals()方法 class C { public int hashCode() { return 2; } public boolean equals(Object obj) { return true; } }
public class HashSetTest { public static void main(String[] args) { HashSet books=new HashSet();
//分別向books集合中新增兩個A物件,兩個B物件,兩個C物件
books.add(new A());
books.add(new A());
books.add(new B());
books.add(new B());
books.add(new C());
books.add(new C());
System.out.println(books);
複製程式碼
} }
結果
[B@1, B@1, C@2, A@3bc257, A@785d65]
可以看出,如果兩個物件通過equals()方法比較返回true,但這兩個物件的hashCode方法返回不同的hashCode值時,這將導致HashSet會把這兩個物件儲存在Hash表的不同位置,從而使物件可以新增成功,這就與Set集合的規則有些出入了。所以,我們要明確的是:equals()決定是否可以加入HashSet,而hashCode()決定存放的位置,他們兩者必須同時滿足才能允許一個新元素加入HashSet。
但是要注意的是:如果兩個物件的hashCode相同,但是他們的equals返回值不同,HashSet會在這個位置用鏈式結構來儲存多個物件。而HashSet訪問集合元素時也是根據元素的HashCode的值來快速定位的,這種鏈式結構會導致效能下降。
所以如果需要把某個類的物件儲存到HashSet集合中,我們在重寫這個類的equasl()方法和hashCode()方法時,應該儘量保證兩個物件通過equals()方法畢節哦返回true時,他們hashCode()方法返回值也相等。
LinkedHashSet
import java.util.*;
public class LinkedHashSetTest
{
public static void main(String[] args)
{
LinkedHashSet books=new LinkedHashSet();
books.add('Java1');
books.add('Java2');
System.out.println(books);
//刪除 Java1
books.remove("Java1");
//重新新增 Java1
books.add("Java1");
System.out.println(books);
}
}
輸出
[Java1, Java2] [Java1, Java2]
元素順序總是與新增順序一致,同時要明白的是,LinkedHashSetTest是HashSet的子類,因為它不允許集合元素重複
TreeSet
import java.util.*;
public class Test { public static void main(String[] args) { TreeSet nums = new TreeSet(); //向TreeSet中新增四個Integer物件 nums.add(5); nums.add(2); nums.add(10); nums.add(-9);
//輸出集合元素,看到集合元素已經處於排序狀態
System.out.println(nums);
[-9, 2, 5, 10]
//輸出集合裡的第一個元素
System.out.println(nums.first());
-9
//輸出集合裡的最後一個元素
System.out.println(nums.last());
10
//返回小於4的子集,不包含4
System.out.println(nums.headSet(4));
[-9, 2]
//返回大於5的子集,如果Set中包含5,子集中還包含5
System.out.println(nums.tailSet(5));
[5, 10]
//返回大於等於-3,小於4的子集。
System.out.println(nums.subSet(-3 , 4));
[2]
}
複製程式碼
}
與HashSet集合採用hash演算法來決定元素的儲存位置不同,TreeSet採用紅黑樹的資料結構來儲存集合元素。TreeSet支援兩種排序方式:自然排序,定製排序
1.自然排序
TreeSet 會呼叫集合元素的compareTo(Object obj)方法來比較元素之間的太小關係,然後將集合元素按升序排序,即自然排序,如果試圖把一個物件新增到TreeSet時,則該物件的類必須實現Comparable介面,否則程式會丟擲異常。
當把一個物件加入TreeSet集合中時,TreeSet會呼叫該物件的compareTo(Object obj)方法與容器中的其他物件比較大小,然後根據紅黑樹結構找到他的儲存位置。如果兩個物件通過compareTo(Object obj)方法比較相等,新物件將無法新增到TreeSet集合中(牢記Set不允許重複的概念)。
注意:當需要把一個物件放入TreeSet中,重寫改物件對應類的equals()方法是,應該保證該方法時,應該保證該方法與compareTo(Object obj)方法有一致的結果,即如果有兩個物件通過equals()方法比較返回true時,這兩個物件通過compareTo(Object obj)方法比較結果應該也為0(即相等)
對與Set來說,它定義了equals()為唯一性判斷的標準,而對於到了具體的實現,HashSet、TreeSet來說,它們又會有自己特有的唯一性判斷標準,只有同時滿足了才能判定為唯一性
2.定製排序
TreeSet的自然排序是根據集合元素的大小,TreeSet將它們以升序排序。如果我們需要實現定製排序,則可以通過Comparator介面。該介面裡包含一個int compare(to1,to2)方法,該方法使用者比較大小。
import java.util.*;
class M { int age; public M(int age) { this.age = age; } public String toString() { return "M[age:" + age + "]"; } }
public class Test { public static void main(String[] args) { TreeSet ts = new TreeSet(new Comparator() { //根據M物件的age屬性來決定大小 public int compare(Object o1, Object o2) { M m1 = (M)o1; M m2 = (M)o2; return m1.age > m2.age ? -1 : m1.age < m2.age ? 1 : 0; } }); ts.add(new M(5)); ts.add(new M(-3)); ts.add(new M(9)); System.out.println(ts); } }
EnumSet
import java.util.*;
enum Season { SPRING,SUMMER,FALL,WINTER } public class EnumSetTest { public static void main(String[] args) { //建立一個EnumSet集合,集合元素就是Season列舉類的全部列舉值 EnumSet es1 = EnumSet.allOf(Season.class); //輸出[SPRING,SUMMER,FALL,WINTER] System.out.println(es1);
//建立一個EnumSet空集合,指定其集合元素是Season類的列舉值。
EnumSet es2 = EnumSet.noneOf(Season.class);
//輸出[]
System.out.println(es2);
//手動新增兩個元素
es2.add(Season.WINTER);
es2.add(Season.SPRING);
//輸出[SPRING,WINTER]
System.out.println(es2);
//以指定列舉值建立EnumSet集合
EnumSet es3 = EnumSet.of(Season.SUMMER , Season.WINTER);
//輸出[SUMMER,WINTER]
System.out.println(es3);
EnumSet es4 = EnumSet.range(Season.SUMMER , Season.WINTER);
//輸出[SUMMER,FALL,WINTER]
System.out.println(es4);
//新建立的EnumSet集合的元素和es4集合的元素有相同型別,
//es5的集合元素 + es4集合元素 = Season列舉類的全部列舉值
EnumSet es5 = EnumSet.complementOf(es4);
//輸出[SPRING]
System.out.println(es5);
}
複製程式碼
}
輸出
[SPRING, SUMMER, FALL, WINTER] [] [SPRING, WINTER] [SUMMER, WINTER] [SUMMER, FALL, WINTER] [SPRING]
以上是Set集合類的Demo,下面講講如何選擇這些集合類呢?
(1)HashSet的效能總是比TreeSet好(貼別是最常用的新增、查詢元素等操作),因為TreeSet需要額外的紅黑樹演算法來維護集合元素的次序。只有當需要一個保持排序的Set時,才應該使用TreeSet,否則都應該使用HashSet
(2)對於普通的插入,刪除操作,LinkedHashSet比HashSet略慢一線,這是由於維護連結串列所帶來的開銷造成的。不過,因為有了連結的存在,遍歷LinkedHashSet會更快
(3)EnumSet是所有Set實現類中效能最好的,但它只能儲存一個列舉類的列舉值作為集合元素。
(4)HashSet,TreeSet,EnumSet都是“執行緒不安全”的。
2.List
ArrayList
如果一開始就知道ArrayList集合需要儲存多少元素,則可以在建立他們時就指定大小,這樣可以減少重新分配的次數,提供效能,ArrayList還提供瞭如下方法來重新分配Object[]陣列。
- ensureCapacity(int minCapacity): 將ArrayList集合的Object[]陣列長度增加minCapacity
- trimToSize(): 調整ArrayList集合的Object[]陣列長度為當前元素的個數。 程式可以通過此方法來減少ArrayList集合物件佔用的記憶體空間
import java.util.*;
public class Test { public static void main(String[] args) { List books = new ArrayList(); //向books集合中新增三個元素 books.add(new String("輕量級Java EE企業應用實戰")); books.add(new String("瘋狂Java講義")); books.add(new String("瘋狂Android講義")); System.out.println(books);
//將新字串物件插入在第二個位置
books.add(1, new String("瘋狂Ajax講義"));
for (int i = 0; i < books.size(); i++) {
System.out.println(books.get(i));
}
//刪除第三個元素
books.remove(2);
System.out.println(books);
//判斷指定元素在List集合中位置:輸出1,表明位於第二位
System.out.println(books.indexOf(new String("瘋狂Ajax講義"))); //①
//將第二個元素替換成新的字串物件
books.set(1, new String("LittleHann"));
System.out.println(books);
//將books集合的第二個元素(包括)
//到第三個元素(不包括)擷取成子集合
System.out.println(books.subList(1, 2));
}
複製程式碼
}
輸出
[輕量級Java EE企業應用實戰, 瘋狂Java講義, 瘋狂Android講義] 輕量級Java EE企業應用實戰 瘋狂Ajax講義 瘋狂Java講義 瘋狂Android講義 [輕量級Java EE企業應用實戰, 瘋狂Ajax講義, 瘋狂Android講義] 1 [輕量級Java EE企業應用實戰, LittleHann, 瘋狂Android講義] [LittleHann]
Stack
注意Stack的後進先出的特點
import java.util.*;
public class Test { public static void main(String[] args) { Stack v = new Stack(); //依次將三個元素push入"棧" v.push("瘋狂Java講義"); v.push("輕量級Java EE企業應用實戰"); v.push("瘋狂Android講義");
//輸出:[瘋狂Java講義, 輕量級Java EE企業應用實戰 , 瘋狂Android講義]
System.out.println(v);
//訪問第一個元素,但並不將其pop出"棧",輸出:瘋狂Android講義
System.out.println(v.peek());
//依然輸出:[瘋狂Java講義, 輕量級Java EE企業應用實戰 , 瘋狂Android講義]
System.out.println(v);
//pop出第一個元素,輸出:瘋狂Android講義
System.out.println(v.pop());
//輸出:[瘋狂Java講義, 輕量級Java EE企業應用實戰]
System.out.println(v);
}
複製程式碼
}
輸出
[瘋狂Java講義, 輕量級Java EE企業應用實戰, 瘋狂Android講義] 瘋狂Android講義 [瘋狂Java講義, 輕量級Java EE企業應用實戰, 瘋狂Android講義] 瘋狂Android講義 [瘋狂Java講義, 輕量級Java EE企業應用實戰]
LinkedList
import java.util.*;
public class Test { public static void main(String[] args) { LinkedList books = new LinkedList();
//將字串元素加入佇列的尾部(雙端佇列)
books.offer("瘋狂Java講義");
//將一個字串元素加入棧的頂部(雙端佇列)
books.push("輕量級Java EE企業應用實戰");
//將字串元素新增到佇列的頭(相當於棧的頂部)
books.offerFirst("瘋狂Android講義");
for (int i = 0; i < books.size() ; i++ )
{
System.out.println(books.get(i));
}
//訪問、並不刪除棧頂的元素
System.out.println(books.peekFirst());
//訪問、並不刪除佇列的最後一個元素
System.out.println(books.peekLast());
//將棧頂的元素彈出"棧"
System.out.println(books.pop());
//下面輸出將看到佇列中第一個元素被刪除
System.out.println(books);
//訪問、並刪除佇列的最後一個元素
System.out.println(books.pollLast());
//下面輸出將看到佇列中只剩下中間一個元素:
//輕量級Java EE企業應用實戰
System.out.println(books);
}
複製程式碼
}
輸出
瘋狂Android講義 輕量級Java EE企業應用實戰 瘋狂Java講義 瘋狂Android講義 瘋狂Java講義 瘋狂Android講義 [輕量級Java EE企業應用實戰, 瘋狂Java講義] 瘋狂Java講義 [輕量級Java EE企業應用實戰]
Queue
import java.util.*;
public class PriorityQueueTest { public static void main(String[] args) { PriorityQueue pq = new PriorityQueue(); //下面程式碼依次向pq中加入四個元素 pq.offer(6); pq.offer(-3); pq.offer(9); pq.offer(0);
//輸出pq佇列,並不是按元素的加入順序排列,
//而是按元素的大小順序排列,輸出[-3, 0, 9, 6]
System.out.println(pq);
//訪問佇列第一個元素,其實就是佇列中最小的元素:-3
System.out.println(pq.poll());
}
複製程式碼
}
PriorityQueue不允許插入null元素,它還需要對佇列元素進行排序,PriorityQueue的元素有兩種排序方式
1) 自然排序: 採用自然順序的PriorityQueue集合中的元素物件都必須實現了Comparable介面,而且應該是同一個類的多個例項,否則可能導致ClassCastException異常
2) 定製排序 建立PriorityQueue佇列時,傳入一個Comparator物件,該物件負責對佇列中的所有元素進行排序 關於自然排序、定製排序的原理和之前說的TreeSet類似
ArrayDeque
import java.util.*;
public class Test { public static void main(String[] args) { ArrayDeque stack = new ArrayDeque(); //依次將三個元素push入"棧" stack.push("瘋狂Java講義"); stack.push("輕量級Java EE企業應用實戰"); stack.push("瘋狂Android講義");
//輸出:[瘋狂Java講義, 輕量級Java EE企業應用實戰 , 瘋狂Android講義]
System.out.println(stack);
//訪問第一個元素,但並不將其pop出"棧",輸出:瘋狂Android講義
System.out.println(stack.peek());
//依然輸出:[瘋狂Java講義, 輕量級Java EE企業應用實戰 , 瘋狂Android講義]
System.out.println(stack);
//pop出第一個元素,輸出:瘋狂Android講義
System.out.println(stack.pop());
//輸出:[瘋狂Java講義, 輕量級Java EE企業應用實戰]
System.out.println(stack);
}
複製程式碼
}
[瘋狂Android講義, 輕量級Java EE企業應用實戰, 瘋狂Java講義] 瘋狂Android講義 [瘋狂Android講義, 輕量級Java EE企業應用實戰, 瘋狂Java講義] 瘋狂Android講義 [輕量級Java EE企業應用實戰, 瘋狂Java講義]
以上就是List集合類的程式設計應用場景。我們來梳理一下思路
java提供的List就是一個“線性表介面”,ArrayList(基於陣列的線性表),LinkedList(基於鏈的線性表)是線性表的兩種典型實現
Queue代表了佇列,Deque代表了雙端佇列(即可以作為佇列使用,也可以作為棧使用)
因為陣列以一塊連續記憶體來儲存所有的陣列元素,所以陣列在隨機訪問時效能最好。
內部以連結串列作為底層實現的集合在執行插入,刪除操作時有很好的的效能
遍歷
我們之前說過,Collection介面繼承了Iterable介面,也就是說,我們以上學習到的所有的Collection集合類都具有"可遍歷性"
Iterable介面也是java集合框架的成員,它隱藏了各種Collection實現類的底層細節,嚮應用程式提供了遍歷Collection集合元素的統一程式設計介面:
- boolean hasNext(): 是否還有下一個未遍歷過的元素
- Object next(): 返回集合裡的下一個元素
- void remove(): 刪除集合裡上一次next方法返回的元素 iteration
import java.util.*;
public class Test { public static void main(String[] args) { //建立一個集合 Collection books=new HashSet(); books.add("1"); books.add("2"); books.add("3"); //獲取books集合對應的迭代器 Iterator it=books.iterator(); while(it.hasNext()) { String book=(String)it.next(); System.out.println(book); if (book.equals("2")) { //從集合中刪除上一次next方法返回的元素 it.remove(); } //對book變數賦值,不會改變集合元素本身 book = "測試字串"; } System.out.println(books);
}
複製程式碼
}
輸出
3 2 1 [3, 1]
從程式碼可以看出,iterator必須依附於Collection物件,若有一個iterator物件,必然有一個與之關聯的Collection物件。
除了可以使用iterator介面迭代訪問Collection集合裡的元素之外,使用java5提供的foreach迴圈迭代訪問集合元素更加便捷
foreach 實現遍歷
import java.util.*;
public class Test { public static void main(String[] args) { //建立一個集合 Collection books = new HashSet(); books.add(new String("1")); books.add(new String("2")); books.add(new String("3"));
for (Object obj : books)
{
//此處的book變數也不是集合元素本身
String book = (String)obj;
System.out.println(book);
if (book.equals("2"))
{
//下面程式碼會引發ConcurrentModificationException異常
//books.remove(book);
}
}
System.out.println(books);
}
複製程式碼
}
輸出
3 2 1 [3, 2, 1]
Map
HashMap,HashTable
import java.util.*;
class A { int count; public A(int count) { this.count = count; } //根據count的值來判斷兩個物件是否相等。 public boolean equals(Object obj) { if (obj == this) return true; if (obj!=null && obj.getClass()==A.class) { A a = (A)obj; return this.count == a.count; } return false; } //根據count來計算hashCode值。 public int hashCode() { return this.count; } } class B { //重寫equals()方法,B物件與任何物件通過equals()方法比較都相等 public boolean equals(Object obj) { return true; } } public class Test { public static void main(String[] args) { Hashtable ht = new Hashtable(); ht.put(new A(60000) , "瘋狂Java講義"); ht.put(new A(87563) , "輕量級Java EE企業應用實戰"); ht.put(new A(1232) , new B()); System.out.println(ht);
//只要兩個物件通過equals比較返回true,
//Hashtable就認為它們是相等的value。
//由於Hashtable中有一個B物件,
//它與任何物件通過equals比較都相等,所以下面輸出true。
System.out.println(ht.containsValue("測試字串")); //①
//只要兩個A物件的count相等,它們通過equals比較返回true,且hashCode相等
//Hashtable即認為它們是相同的key,所以下面輸出true。
System.out.println(ht.containsKey(new A(87563))); //②
//下面語句可以刪除最後一個key-value對
ht.remove(new A(1232)); //③
//通過返回Hashtable的所有key組成的Set集合,
//從而遍歷Hashtable每個key-value對
for (Object key : ht.keySet())
{
System.out.print(key + "---->");
System.out.print(ht.get(key) + "\n");
}
}
複製程式碼
}
輸出
{A@ea60=瘋狂Java講義, A@1560b=輕量級Java EE企業應用實戰, A@4d0=B@547c9586} true true A@ea60---->瘋狂Java講義 A@1560b---->輕量級Java EE企業應用實戰
當使用自定義類作為HashMap,Hashtable的key時,如果重寫該類的equals(Object obj)和hashCode()方法,則應該保證兩個方法的判斷標準一致-當兩個key通過equals()方法比較返回true時,兩個key的hashCode()的返回值也應該相同。
LinkedHashMap
import java.util.*;
public class Test { public static void main(String[] args) { LinkedHashMap scores = new LinkedHashMap(); scores.put("語文" , 80); scores.put("英文" , 82); scores.put("數學" , 76); //遍歷scores裡的所有的key-value對 for (Object key : scores.keySet()) { System.out.println(key + "------>" + scores.get(key)); } } }
輸出
語文------>80 英文------>82 數學------>76
properties
import java.util.; import java.io.;
public class Test { public static void main(String[] args) throws Exception { Properties props = new Properties(); //向Properties中增加屬性 props.setProperty("username" , "yeeku"); props.setProperty("password" , "123456");
//將Properties中的key-value對儲存到a.ini檔案中
props.store(new FileOutputStream("a.ini"), "comment line"); //①
//新建一個Properties物件
Properties props2 = new Properties();
//向Properties中增加屬性
props2.setProperty("gender" , "male");
//將a.ini檔案中的key-value對追加到props2中
props2.load(new FileInputStream("a.ini") ); //②
System.out.println(props2);
}
複製程式碼
}
輸出
{password=123456, gender=male, username=yeeku}
TreeMap
import java.util.*;
class R implements Comparable { int count; public R(int count) { this.count = count; } public String toString() { return "R[count:" + count + "]"; } //根據count來判斷兩個物件是否相等。 public boolean equals(Object obj) { if (this == obj) return true; if (obj!=null && obj.getClass()==R.class) { R r = (R)obj; return r.count == this.count; } return false; } //根據count屬性值來判斷兩個物件的大小。 public int compareTo(Object obj) { R r = (R)obj; return count > r.count ? 1 : count < r.count ? -1 : 0; } } public class TreeMapTest { public static void main(String[] args) { TreeMap tm = new TreeMap(); tm.put(new R(3) , "輕量級Java EE企業應用實戰"); tm.put(new R(-5) , "瘋狂Java講義"); tm.put(new R(9) , "瘋狂Android講義");
System.out.println(tm);
//返回該TreeMap的第一個Entry物件
System.out.println(tm.firstEntry());
//返回該TreeMap的最後一個key值
System.out.println(tm.lastKey());
//返回該TreeMap的比new R(2)大的最小key值。
System.out.println(tm.higherKey(new R(2)));
//返回該TreeMap的比new R(2)小的最大的key-value對。
System.out.println(tm.lowerEntry(new R(2)));
//返回該TreeMap的子TreeMap
System.out.println(tm.subMap(new R(-1) , new R(4)));
}
複製程式碼
}
輸出
{R[count:-5]=瘋狂Java講義, R[count:3]=輕量級Java EE企業應用實戰, R[count:9]=瘋狂Android講義} R[count:-5]=瘋狂Java講義 R[count:9] R[count:3] R[count:-5]=瘋狂Java講義 {R[count:3]=輕量級Java EE企業應用實戰}
從程式碼中可以看出,類似於TreeSet中判斷兩個元素是否相等的標準,TreeMap中判斷兩個key相等的標準是
- 兩個key通過compareTo()方法返回0
- equals()放回true
EnumMap
import java.util.*;
enum Season { SPRING,SUMMER,FALL,WINTER } public class Test { public static void main(String[] args) { //建立一個EnumMap物件,該EnumMap的所有key //必須是Season列舉類的列舉值 EnumMap enumMap = new EnumMap(Season.class); enumMap.put(Season.SUMMER , "夏日炎炎"); enumMap.put(Season.SPRING , "春暖花開"); System.out.println(enumMap); } }
輸出
{SPRING=春暖花開, SUMMER=夏日炎炎}
與建立普通Map有所區別的是,建立EnumMap是必須指定一個列舉類,從而將該EnumMap和指定列舉類關聯起來
以上就是Map集合類的程式設計小demo。我們來梳理一下思路
(1)HashMap和Hashtable的效率大致相同,因為它們的實現機制幾乎完全一樣。但HashMap通常比Hashtable要快一點,因為Hashtable需要二外的執行緒同步控制
(2)TreeMap通常比HashMap,Hashtable要慢(尤其是在插入,刪除key-value對要慢),因為TreeMap底層採用的