Map用于保存具有映射關(guān)系的數(shù)據(jù),因此Map集合中保存著兩組值,一組值用于保存Map里的key,另外一組值用于保存Map里的value,key和value都可以是任何引用類型的數(shù)據(jù)。Map的key不允許重復(fù),即同一個Map對象的任何兩個key通過equals()方法比較總是返回false。
如果把Map里的所有key放在一起來看,它們就組成了一個Set集合(所有的key沒有順序,key和key之間不能重復(fù)),實際上,Map確實包含了一個keySet()方法,用于返回Map里所有的key組成的Set集合。
如果把Map里的所有value放在一起看,它們又非常類似于一個List:元素與元素之間可以重復(fù),每個元素可以根據(jù)索引來查找,只是Map中的索引不再使用整數(shù)值,而是以另一個對象作為索引。如果需要從Map中取出元素,需要提供該元素的key索引。因此,Map有時也被稱為字典,或關(guān)聯(lián)數(shù)組。
Map接口中定義的常用方法有:

這里要注意的是V put(K key, V value)方法,該方法用于給Map中添加新的鍵值對,如果放入重復(fù)的key時,新的value會覆蓋原有的value;如果新的value覆蓋了原有的value,該方法會返回被覆蓋的value。當(dāng)然,如果沒有key重復(fù),也就沒有覆蓋,該方法返回null。
測試如下:
public static void main(String[] args) { HashMap<String, String> hm = new HashMap<>(); hm.put("a", "123"); System.out.輸出如下:null123第一次輸出,并沒有覆蓋,所以方法返回null;第二次輸出,由于Map中已經(jīng)有了a這個鍵,所以原有的123被覆蓋并返回。
HashMap和Hashtable都是Map接口的典型實現(xiàn)類,它們之間的關(guān)系完全類似于ArrayList和Vector的關(guān)系:Hashtable是一個古老的Map實現(xiàn)類,它從JDK1.0起就出現(xiàn)了,當(dāng)它出現(xiàn)時,java還沒有提供Map接口。
HashMap與Hashtable存在兩點典型區(qū)別:
Hashtable是一個線程安全的Map實現(xiàn),但HashMap是線程不安全的實現(xiàn),所以HashMap比Hashtable的性能高一點;但如果有多個線程訪問同一個Map對象時,使用Hashtable實現(xiàn)類會更好。2.Hashtable不允許使用null作為key和value,但HashMap可以。為了成功地在HashMap、Hashtable中存儲、獲取對象,用作key的對象必須實現(xiàn)hashCode()方法和equals()方法。
與HashSet集合不能保證元素順序一樣,HashMap和Hashtable也不能保證其中的key-value對的順序。類似于HashSet,HashMap和Hashtable判斷兩個key相等的標(biāo)準(zhǔn)也是:兩個key的hashCode值相等,兩個key通過equals()方法比較返回true。
除此之外,HashMap和Hashtable中還包含一個containsValue()方法,用于判斷是否包含指定的value。那么HashMap和Hashtable判斷兩個value相等的標(biāo)準(zhǔn)是什么呢?這個標(biāo)準(zhǔn)更簡單一點:只要兩個對象通過equals()方法比較返回true即可。
我們可以做如下測試:
class A { private int count; public A(int count){ this.count = count; } // 根據(jù)count的值來判斷兩個對象是否相等 public boolean equals(Object obj){ if(this == obj){ return true; } if(obj == null){ return false; } if(this.getClass() != obj.getClass()){ return false; } A a = (A)obj; return this.count == a.count; } // 根據(jù)count來計算hashCode值 public int hashCode(){ return this.count; }}class B{ @Override public boolean equals(Object obj) { return true; }}public class HashtableTest { public static void main(String[] args) { Hashtable ht = new Hashtable<>(); ht.put(new A(1000),"Java"); ht.put(new A(2000),"Python"); ht.put(new A(3000),new B()); //由于Hashtable中有一個B對象,它與任何對象通過equals()方法比較都返回true // 所以這里不管測試的字符串是什么,它都會返回true System.out.println(ht.containsValue("123")); // 對于key來說,如果兩個A對象的hashCode值相等,并且通過equals()方法比較返回true // 那么它們就是相等的,就是相同的key System.out.println(ht.containsKey(new A(1000))); }}程序輸出:
truetrue1.因為HashMap、Hashtable保存key的方式與HashSet保存集合元素的方式完全相同,所以HashMap、Hashtable對key的要求與HashSet對集合元素的要求完全相同。 2.也就是說,當(dāng)使用自定義類作為HashMap、Hashtable的key時,如果重寫該類的equals(Object obj)和hashCode()方法,則應(yīng)該保證兩個方法的判斷標(biāo)準(zhǔn)一致:當(dāng)兩個key通過equals()方法比較返回true時,兩個key的hashCode()返回值也應(yīng)該相同。
HashSet有一個LinkedHashSet子類,HashMap也有一個LinkedHashMap子類。LinkedHashMap使用雙向鏈表來維護key-value對的次序(其實只需要考慮key的次序),該鏈表負(fù)責(zé)維護Map的迭代順序,迭代順序與key-value對的插入順序保持一致。
LinkedHashMap需要維護元素的插入順序,因此性能略低于HashMap的性能;但因為它以鏈表來維護內(nèi)部順序,所以在使用迭代器訪問全部元素時有比較好的性能。
程序輸出:
語文-->90數(shù)學(xué)-->100英語-->95正如Set接口派生出SortedSet子接口,SortedSet接口有一個TreeSet實現(xiàn)類一樣,Map接口也派生出一個SortedMap子接口,SortedMap接口也有一個TreeMap實現(xiàn)類。
TreeMap就是一個紅黑樹數(shù)據(jù)結(jié)構(gòu),每個key-value對即作為紅黑樹的一個節(jié)點。TreeMap存儲key-value對時,需要根據(jù)key對節(jié)點進(jìn)行排序。TreeMap可以保證所有的key-value對處于有序狀態(tài)。TreeMap也有兩種排序方式:
TreeMap的所有key必須實現(xiàn)Comparable接口,而且所有的key應(yīng)該是同一個類的對象,否則將會拋出ClassCastException異常。2.定制排序:創(chuàng)建TreeMap時,傳入一個Comparator對象,該對象負(fù)責(zé)對TreeMap中的所有key進(jìn)行排序。采用定制排序不需要Map的key實現(xiàn)Comparable接口。類似于TreeSet中判斷兩個元素相等的標(biāo)準(zhǔn),TreeMap中判斷兩個key相等的標(biāo)準(zhǔn)是:兩個key通過compareTo()方法返回0。
與TreeSet類似的是,TreeMap中也提供了一系列根據(jù)key順序訪問key-value對的方法:
| 方法 | 說明 |
|---|---|
Map.Entry<K,V> firstEntry() | 返回一個與此映射中的最小鍵關(guān)聯(lián)的鍵-值映射關(guān)系;如果映射為空,則返回 null |
K lastKey() | 返回此映射中當(dāng)前第一個(最低)鍵,如果映射為空,則返回 null |
Map.Entry<K,V> lastEntry() | 返回與此映射中的最大鍵關(guān)聯(lián)的鍵-值映射關(guān)系;如果映射為空,則返回 null |
K lastKey() | 返回此映射中當(dāng)前最后一個(最高)鍵,如果映射為空,則返回 null |
Map.Entry<K,V> higherEntry(K key) | 返回一個鍵-值映射關(guān)系,它與嚴(yán)格大于給定鍵的最小鍵關(guān)聯(lián);如果不存在這樣的鍵,則返回 null |
K higherKey(K key) | 返回嚴(yán)格大于給定鍵的最小鍵;如果不存在這樣的鍵,則返回 null |
Map.Entry<K,V> lowerEntry(K key) | 返回一個鍵-值映射關(guān)系,它與嚴(yán)格小于給定鍵的最大鍵關(guān)聯(lián);如果不存在這樣的鍵,則返回 null |
K lowerKey(K key) | 返回嚴(yán)格小于給定鍵的最大鍵;如果不存在這樣的鍵,則返回 null |
NavigableMap<K,V> subMap(K fromKey,boolean fromInclusive,K toKey,boolean toInclusive) | 返回該Map的子Map,其key范圍是從fromKey(是否包括取決于第二個參數(shù))到toKey(是否包括取決于第四個參數(shù)) |
SortedMap<K,V> subMap(K fromKey,K toKey) | 返回此Map的子Map,其key范圍是從fromKey(包括)到toKey(不包括) |
SortedMap<K,V> tailMap(K fromKey) | 返回該Map的子Map,其key的范圍是大于fromKey(包括)的所有key |
NavigableMap<K,V> tailMap(K fromKey,boolean inclusive) | 返回該Map的子Map,其key的范圍是大于fromKey(是否包括取決于第二個參數(shù))的所有key |
SortedMap<K,V> headMap(K toKey) | 返回該Map的子Map,其key的范圍是小于toKey(不包括)的所有key |
NavigableMap<K,V> headMap(K toKey,boolean inclusive) | 返回該Map的子Map,其key的范圍是小于toKey(是否包括取決于第二個參數(shù))的所有key |
針對這些方法做測試如下:
class R implements Comparable{ int count; public R(int count) { this.count = count; } //根據(jù)count值判斷兩個對象是否相等 @Override public boolean equals(Object obj) { if(this == obj) return true; if(obj == null || this.getClass() != obj.getClass()) return false; R r = (R)obj; return this.count == r.count; } // 根據(jù)count屬性值來判斷兩個對象的大小 @Override public int compareTo(Object o) { R r = (R)o; return this.count > r.count ? 1: this.count < r.count ? -1 : 0; } @Override public String toString() { return "R [count=" + count + "]"; }}public class TreeMapTest { public static void main(String[] args) { TreeMap tm = new TreeMap<>(); tm.put(new R(3),"Java"); tm.put(new R(-5),"Python"); tm.put(new R(9),"C++"); System.out.println(tm); // 返回第一個鍵值對 System.out.println(tm.firstEntry()); // 返回最后一個鍵 System.out.println(tm.lastKey()); // 返回比new R(2)大的最小的key-value對 System.out.println(tm.higherEntry(new R(2))); // 返回比new R(2)小的最大key值 System.out.println(tm.lowerKey(new R(2))); // 返回key在new R(-1)和new R(4)之間的子Map System.out.println(tm.subMap(new R(-1), new R(4))); }}程序輸出:
{R [count=-5]=Python, R [count=3]=Java, R [count=9]=C++}R [count=-5]=PythonR [count=9]R [count=3]=JavaR [count=-5]{R [count=3]=Java}新聞熱點
疑難解答
圖片精選