摘要:和之間存在單向一對(duì)一關(guān)系,即通過(guò)指定的,總能找到唯一的確定的。從中取出數(shù)據(jù)時(shí),只要給出指定的,就可以取出對(duì)應(yīng)的。有時(shí)也稱(chēng)為字典,或關(guān)聯(lián)數(shù)組。采用定制排序時(shí)不要求的實(shí)現(xiàn)接口中判斷兩個(gè)相等的標(biāo)準(zhǔn)是兩個(gè)通過(guò)方法返回,即認(rèn)為這兩個(gè)是相等的。
map用于保存具有映射關(guān)系的數(shù)據(jù),因此Map集合里保存著兩組值,一組值用于保存Map里的key,另外一組值用于保存Map里的value,key和value都可以是任何引用類(lèi)型的數(shù)據(jù)。Map的key不允許重復(fù),即同一個(gè)Map對(duì)象的任何兩個(gè)key通過(guò)equals方法比較總是返回false。key和value之間存在單向一對(duì)一關(guān)系,即通過(guò)指定的key,總能找到唯一的、確定的value。從Map中取出數(shù)據(jù)時(shí),只要給出指定的key,就可以取出對(duì)應(yīng)的value。
Map有時(shí)也稱(chēng)為字典,或關(guān)聯(lián)數(shù)組。Map接口中定義如下方法:
void clear():刪除Map對(duì)象中所有key-value對(duì)
boolean containsKey(Object key):查詢(xún)Map中是否包含指定key,如果包含則返回true
boolean containsValue(Object value):查詢(xún)Map中是否包含一個(gè)或多個(gè)value,如果包含則返回true
Set entrySet():返回Map中所有包含的key-value對(duì)組成的Set集合,每個(gè)集合元素都是Map.Entry(Entry是Map的內(nèi)部類(lèi))對(duì)象
Object get(Obejct key):返回指定key所對(duì)應(yīng)的value;如果此Map中不包含key,則返回null
boolean isEmpty():查詢(xún)?cè)揗ap是否為空(即不包含任何key-value對(duì)),如果為空則返回true
Set keySet():返回該Map中所有key所組成的set集合
Object put(Object key, Object value):添加一個(gè)key-value對(duì),如果當(dāng)前Map中已有一個(gè)與該key相等的key-value對(duì),則新的key-value對(duì)會(huì)覆蓋原來(lái)的key-value對(duì)
Object remove(Object key):刪除指定key對(duì)應(yīng)的key-value對(duì),返回被刪除key所關(guān)聯(lián)的value,如果該key不存在,返回null
int size():返回該Map里的key-value對(duì)的個(gè)數(shù)
Collection values():返回該Map里所有value組成的Collection
Map中包括一個(gè)內(nèi)部類(lèi):Entry。該類(lèi)封裝了一個(gè)key-value對(duì),Entry包含三個(gè)方法:
Object getkey():返回該Entry里包含的key值
Object getValue():返回該Entry里包含的value值
Object setValue():設(shè)置該Entry里包含的value值,并返回新設(shè)置的value值
import java.util.*; public class MapTest { public static void main(String[] args) { Map map = new HashMap(); // 成對(duì)放入多個(gè)key-value對(duì) map.put("勒布朗詹姆斯", 6); map.put("凱文杜蘭特", 35); map.put("斯蒂芬?guī)炖?, 30); // 多次放入的key-value對(duì)中value可以重復(fù) map.put("維斯布魯克", 0); // 放入重復(fù)的key時(shí),新的value會(huì)覆蓋原有的value // 如果新的value覆蓋了原有的value,該方法返回被覆蓋的value System.out.println(map.put("勒布朗詹姆斯", 23)); // 輸出6 System.out.println(map); // 輸出的Map集合包含4個(gè)key-value對(duì) // 輸出{凱文杜蘭特=35, 勒布朗詹姆斯=23, 斯蒂芬?guī)炖?30, 維斯布魯克=0} // 判斷是否包含指定key System.out.println("是否包含值為 勒布朗詹姆斯 key:" + map.containsKey("勒布朗詹姆斯")); // 輸出true // 判斷是否包含指定value System.out.println("是否包含值為 0 value:" + map.containsValue(0)); // 輸出true // 獲取Map集合的所有key組成的集合,通過(guò)遍歷key來(lái)實(shí)現(xiàn)遍歷所有key-value對(duì) for (Object key : map.keySet() ) { // map.get(key)方法獲取指定key對(duì)應(yīng)的value System.out.println(key + "-->" + map.get(key)); } map.remove("凱文杜蘭特"); // 根據(jù)key來(lái)刪除key-value對(duì)。 System.out.println(map); // 輸出結(jié)果不再包含 瘋狂凱文杜蘭特=35 的key-value對(duì) } }
Map的實(shí)現(xiàn)類(lèi)都重寫(xiě)了toString()方法,調(diào)用Map對(duì)象的toString()方法總是返回如下格式的字符串:{key1=value, key2=value...}
Java8為Map新增的方法Java8除了為map增加了remove(Object key, Object value)默認(rèn)方法之外,還增加了如下方法:
Object compute(Object key, BiFunction remappingFunction):該方法使用remappingFunction根據(jù)原key-value對(duì)計(jì)算一個(gè)新value。只要新value不為null,就使用新value覆蓋原value;如果原value不為null,但新value為null,則刪除原key-value對(duì);如果原value、新value同時(shí)為null,那么該方法不改變?nèi)魏蝛ey-value對(duì),直接返回null
Object computeIfAbsent(Object key, Function mappingFunction):如果傳給該方法的key參數(shù)在Map中對(duì)應(yīng)的value為null,則使用mappingFunction根據(jù)key計(jì)算一個(gè)新的結(jié)果,如果計(jì)算結(jié)果不為null,則用計(jì)算結(jié)果覆蓋原有value。如果原Map原來(lái)不包含該key,那么該方法可能會(huì)添加一組key-value對(duì)
Object computeIfPresent(Object key ,BiFunction remappingFunction):如果傳給該方法的key參數(shù)在Map中對(duì)應(yīng)的value不為null,該方法將使用remappingFunction根據(jù)原key、value計(jì)算一個(gè)新的結(jié)果,如果計(jì)算結(jié)果不為null,則使用該結(jié)果覆蓋原來(lái)的value,如果計(jì)算的結(jié)果為null,則刪除原key-value對(duì)
void forEach(BiConsumer action):該方法是Java 8為Map新增的一個(gè)遍歷key-value對(duì)的方法
Object getOrDefault(Object key, V defaultValue):獲取指定key對(duì)應(yīng)的value。如果該key不存在則返回defaultValue
Object merge(Object key, Object value, BiFunction remappingFunction):該方法會(huì)先根據(jù)Key參數(shù)獲取該Map中對(duì)應(yīng)的value。如果獲得value為null,則直接用傳入的value覆蓋原有的value(在這中情況下,可能要添加一組key-value對(duì));如果獲取的value不為null,則使用remappingFunction 函數(shù)根據(jù)原value、新value計(jì)算一新的結(jié)果,并用得到的結(jié)果去覆蓋原有的value
Object putIfAbsent(Object key, Object value):該方法會(huì)自動(dòng)檢測(cè)指定key對(duì)應(yīng)的value是否為null,如果該key對(duì)應(yīng)的value為null,該方法將會(huì)用新value代替原來(lái)的null值
Object replace(Object key, Object value):將Map中指定key對(duì)應(yīng)的value替換成新的value。與傳統(tǒng)的put方法不同的是,該方法不可能添加新的key-value對(duì)。如果嘗試替換的key在原Map中不存在,該方法不會(huì)添加key-value對(duì),而是返回null
boolean replace(K key, V oldValue, V newValue)
將Map中指定key-value對(duì)的原value提換成新value。如果在Map中找到指定的key-value對(duì),則執(zhí)行替換并返回true,否額返回false
replaceAll(Bifunction function):該方法使用Bifunction 對(duì)原key-value對(duì)執(zhí)行計(jì)算,并將計(jì)算結(jié)果作為key-value對(duì)的value的值
import java.util.*; public class MapTest2 { public static void main(String[] args) { Map map = new HashMap(); // 成對(duì)放入多個(gè)key-value對(duì) map.put("勒布朗詹姆斯", 6); map.put("凱文杜蘭特", 35); map.put("斯蒂芬?guī)炖?, 30); // 嘗試替換key為"維斯布魯克"的value,由于原Map中沒(méi)有對(duì)應(yīng)的key, // 因此對(duì)Map沒(méi)有改變,不會(huì)添加新的key-value對(duì) map.replace("維斯布魯克", 0); System.out.println(map); // 使用原value與參數(shù)計(jì)算出來(lái)的結(jié)果覆蓋原有的value map.merge("勒布朗詹姆斯", 17 , (oldVal , param) -> (Integer)oldVal + (Integer)param); System.out.println(map); // "勒布朗詹姆斯"的value增大了17,變?yōu)?3 // 當(dāng)key為"詹姆斯哈登"對(duì)應(yīng)的value為null(或不存在時(shí)),使用計(jì)算的結(jié)果作為新value map.computeIfAbsent("凱文加內(nèi)特" , (key)->((String)key).length()); System.out.println(map); // map中添加了 凱文加內(nèi)特=5 這組key-value對(duì) // 當(dāng)key為"凱文加內(nèi)特"對(duì)應(yīng)的value存在時(shí),使用計(jì)算的結(jié)果作為新value map.computeIfPresent("凱文加內(nèi)特", (key , value) -> (Integer)value + 16); System.out.println(map); // map中 凱文加內(nèi)特=5 變成 凱文加內(nèi)特=21 } }Java8改進(jìn)的HashMap和Hashtable實(shí)現(xiàn)類(lèi)
HashMap和Hashtable都是Map接口的典型實(shí)現(xiàn)類(lèi),它們之間的關(guān)系完全類(lèi)似于ArrayList和Vector的關(guān)系
使用HashMap存在key沖突時(shí)依然具有較好的性能
Hashtable是一個(gè)線(xiàn)程安全的Map實(shí)現(xiàn),但HashMap是線(xiàn)程不安全的實(shí)現(xiàn),所以HashMap比Hashtable的性能高一點(diǎn);但如果有多線(xiàn)程訪(fǎng)問(wèn)同一個(gè)Map對(duì)象時(shí),使用Hashtable實(shí)現(xiàn)類(lèi)會(huì)更好
Hashtable不允許使用null作為key和value,如果試圖把null值放進(jìn)Hashtable中,將會(huì)引發(fā)NullPointerException異常;但HashMap可以使用null作為key或value
由于HashMap里的key不能重復(fù),所以HashMap里最多只有一個(gè)key-value對(duì)的key為null,但可以有無(wú)數(shù)多個(gè)key-value對(duì)的value為null
public class NullInHashMap { public static void main(String[] args) { HashMap hm = new HashMap(); // 試圖將兩個(gè)key為null的key-value對(duì)放入HashMap中 hm.put(null, null); hm.put(null, null); // ① // 將一個(gè)value為null的key-value對(duì)放入HashMap中 hm.put("a", null); // ② // 輸出Map對(duì)象 System.out.println(hm); } }
①代碼處無(wú)法將key-value對(duì)放入,因?yàn)镸ap中已經(jīng)有一個(gè)key-value對(duì)的key為null,所以無(wú)法再放入key為null值的key-value對(duì)
{null=null, a=null}
為了成功的在HashMap、Hashtable中存儲(chǔ)、獲取對(duì)象,用作key的對(duì)象必須實(shí)現(xiàn)hashCode()方法和equals()方法
與HashSet集合不能保證元素的順序一樣,HashMap、Hashtable也不能保證其中key-value對(duì)的順序。類(lèi)似于HashSet的是,HashMap、Hashtable判斷兩個(gè)key相等的標(biāo)準(zhǔn)也是:兩個(gè)key通過(guò)equals方法比較返回true,兩個(gè)key的hashCode值也相等。除此之外,HashMap、Hashtable中還包含一個(gè)containsValue()方法用于判斷是否包含指定value。HashMap、Hashtable判斷兩個(gè)value相等的標(biāo)準(zhǔn)更簡(jiǎn)單:只要兩個(gè)對(duì)象通過(guò)equals比較返回true即可
import java.util.Hashtable; class A { int count; public A(int count) { this.count = count; } // 根據(jù)count的值來(lái)判斷兩個(gè)對(duì)象是否相等 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; } // 根據(jù)count來(lái)計(jì)算hashCode值 public int hashCode() { return this.count; } } class B { // 重寫(xiě)equals()方法,B對(duì)象與任何對(duì)象通過(guò)equals()方法比較都返回ture public boolean equals() { return true; } } public class HashtableTest2 { public static void main(String[] args) { Hashtable ht = new Hashtable<>(); ht.put(new A(23), "勒布朗詹姆斯"); ht.put(new A(0), "凱文樂(lè)福"); // ht.put(new A(2), "凱里歐文"); ht.put(new A(6), new B()); System.out.println(ht); // 只要兩個(gè)對(duì)象通過(guò)equals()方法比較返回true // Hashtable就認(rèn)為它們是相等的value // 由于Hashtable中有一個(gè)B對(duì)象 // 它與任何對(duì)象通過(guò)equals比較都相等,所以下面輸出true System.out.println(ht.containsValue("克利夫蘭騎士")); // ① 輸出true // 只要兩個(gè)A對(duì)象的count相等,它們通過(guò)equals比較返回true,且hashCode相等 // Hashtable即認(rèn)為它們是相同的key,所以下面輸出true System.out.println(ht.containsKey(new A(23))); // ② 輸出true // 下面語(yǔ)句可以刪除最后一個(gè)key-value對(duì) ht.remove(new A(6)); //③ System.out.println(ht); } }
與HashSet類(lèi)似的是,如果使用可變對(duì)象作為HashMap、Hashtable的key,并且程序修改了作為key的可變對(duì)象,可能引發(fā)與HashSet類(lèi)似的情形:程序無(wú)法準(zhǔn)確訪(fǎng)問(wèn)到Map中被修改過(guò)key。 所以說(shuō)盡量不要使用可變對(duì)象作為HashMapHashtable的key
LinkedHashMap實(shí)現(xiàn)類(lèi)HashSet有一個(gè)子類(lèi)是LinkedHashSet,HashMap也有一個(gè)LinkedHashMap子類(lèi);LinkedHashMap也使用雙向鏈表來(lái)維護(hù)key-value對(duì)的次序;該鏈表負(fù)責(zé)維護(hù)key的迭代順序,迭代順序與key-value的插入順序一致
LinkedHashMap可以避免對(duì)HashMap、Hashtable里的key-value對(duì)進(jìn)行排序(只要插入key-value對(duì)時(shí)保持順序即可)。同時(shí)又可避免使用TreeMap所增加的成本
LinkedHashMap需要維護(hù)元素的插入順序,因此性能略低于HashMap的性能,但在迭代訪(fǎng)問(wèn)Map里的全部元素時(shí)將有很好的性能,因?yàn)樗枣湵韥?lái)維護(hù)內(nèi)部順序
public class LinkedHashMapTest { public static void main(String[] args) { LinkedHashMap scores = new LinkedHashMap(); scores.put("勒布朗詹姆斯", 23); scores.put("維斯布魯克", 0); scores.put("斯蒂芬?guī)炖?, 30); // 調(diào)用forEach方法遍歷scores里的所有key-value對(duì) scores.forEach((key, value) -> System.out.println(key + "-->" + value)); } }使用Properties讀取屬性文件
Properties類(lèi)是Hashtable類(lèi)的子類(lèi),用于處理屬性文件(例如Windows操作平臺(tái)上的ini文件)。Properties類(lèi)可以把Map對(duì)象和屬性文件關(guān)聯(lián)起來(lái),從而可以把Map對(duì)象中的key-value對(duì)寫(xiě)入屬性文件,也可以把屬性文件中的“屬性名=屬性值”加載到Map對(duì)象中。由于屬性文件里的屬性名、屬性值只能是字符串類(lèi)型,所以Properties里的key、value都是字符串類(lèi)型
修改Properties里的key、value值的方法
String getProperty(String key):獲取Properties中指定屬性名對(duì)應(yīng)的屬性值,類(lèi)似于Map的get(Object key)方法
String getProperty(String key, String defaultValue):該方法與前一個(gè)方法基本類(lèi)似。該方法多一個(gè)功能,如果Properties中不存在指定key時(shí),該方法返回默認(rèn)值
Object geProperty(String key、String value):設(shè)置屬性值,類(lèi)似Hashtable的put方法
讀、寫(xiě)屬性文件的方法:
void load(InputStream inStream):從屬性文件(以輸入流表示)中加載屬性名=屬性值,把加載到的屬性名=屬性值對(duì)追加到Properties里(由于Properties是Hashtable)的子類(lèi),它不保證key-value對(duì)之間的次序)
void Store(OutputStream out, String comment):將Properties中的key-valu對(duì)寫(xiě)入指定屬性文件(以輸出流表示)
public class PropertiesTest { public static void main(String[] args) throws Exception { Properties props = new Properties(); // 向Properties中增加屬性 props.setProperty("username" , "LeBron"); props.setProperty("teams" , "Cavaliers"); // 將Properties中的key-value對(duì)保存到a.ini文件中 props.store(new FileOutputStream("NBA.ini") , "comment line"); //① // 新建一個(gè)Properties對(duì)象 Properties props2 = new Properties(); // 向Properties中增加屬性 props2.setProperty("gender" , "male"); // 將a.ini文件中的key-value對(duì)追加到props2中 props2.load(new FileInputStream("NBA.ini") ); //② System.out.println(props2); } }SortedMap接口和TreeMap實(shí)現(xiàn)類(lèi)
Map接口派生了一個(gè)SortedMap子接口,TreeMap為其實(shí)現(xiàn)類(lèi)。類(lèi)似TreeSet排序,TreeMap也是基于紅黑樹(shù)對(duì)TreeMap中所有key進(jìn)行排序,從而保證TreeMap中所有key-value對(duì)處于有序狀態(tài)。TreeMap兩種排序方法:
自然排序:TreeMap的所有key必須實(shí)現(xiàn)Comparable接口,而且所有key應(yīng)該是同一個(gè)類(lèi)的對(duì)象,否則將會(huì)拋出ClassCastExcepiton異常
定制排序:創(chuàng)建TreeMap時(shí),傳入一個(gè)Comparator對(duì)象,該對(duì)象負(fù)責(zé)對(duì)TreeMap中所有key進(jìn)行排序。采用定制排序時(shí)不要求Map的key實(shí)現(xiàn)Comparable接口
TreeMap中判斷兩個(gè)key相等的標(biāo)準(zhǔn)是:兩個(gè)key通過(guò)compareTo方法返回0,TreeMap即認(rèn)為這兩個(gè)key是相等的。
如果使用自定義的類(lèi)作為T(mén)reeMap的key,應(yīng)重新該類(lèi)的equals方法和compareTo方法時(shí)應(yīng)有一致的返回結(jié)果:即兩個(gè)key通過(guò)equals方法比較返回true時(shí),它們通過(guò)compareTo方法比較應(yīng)該返回0。如果equals方法與compareTo方法的返回結(jié)果不一致,要么該TreeMap與Map接口的規(guī)則有出入(當(dāng)equals比較返回true,但CompareTo比較不返回0時(shí)),要么TreeMap處理起來(lái)性能有所下降(當(dāng)compareTo比較返回0,當(dāng)equals比較不返回true時(shí))
根據(jù)key順序來(lái)訪(fǎng)問(wèn)Map中key-value對(duì)方法:
Map.Entry firstEntry():返回該Map中最小key所對(duì)應(yīng)的key-value對(duì),如果該Map為空,則返回null
Map.Entry lastEntry():返回該Map中最大key所對(duì)應(yīng)的key-value對(duì),如果該Map為空,或不存在這樣的key-value都返回null
Object firstKey():返回該Map中的最小key值,如果該Map為空,則返回null
Object lastKey():返回該Map中的最大key值,如果該Map為空,或不存在這樣的key都返回null
Map.Entry higherEntry(Object key):返回該Map中位于key后一位的key-value對(duì)(即大于指定key的最小key所對(duì)應(yīng)的key-value對(duì))。如果該Map為空,則返回null
Map.Entry lowerEntry(Object key):返回該Map中位于key前一位的key-value對(duì)(即小于指定key的最大key所對(duì)應(yīng)的key-value對(duì))。如果該Map為空,或不存在這樣的key-value則返回null
Object higherKey():返回該Map中位于key后一位的key值(即大于指定key的最小key值)。如果該Map為空,或不存在這樣的key都返回null
Object lowerKey():返回該Map中位于key前一位的key值(即小于指定key的最大key值)。如果該Map為空,或不存在這樣的key都返回null
NavigableMap subMap(Object fromKey, boolean fromInclusive, Object
tokey, boolean tolnclusive):返回該Map的子Map,其key的范圍從fromKey(是否包括取決于第二個(gè)參數(shù))到tokey(是否包括取決于第四個(gè)參數(shù))。
NavigableMap headMap(Object toKey, boolean lnclusive):返回該Map的子Map,其key的范圍是小于toKey(是否包括取決于第二個(gè)參數(shù))的所有key
NavigableMap tailMap(Object fromKey, boolean lnclusive):返回該Map的子Map,其key的范圍是大于fromKey(是否包括取決于第二個(gè)參數(shù))的所有key
SorterMap subMap(Object fromKey, Object toKey):返回該Map的子Map,其key的范圍從fromKey(包括)到toKey(不包括)
SortedMap headMap(Object toKey):返回該Map的子Map,其key的范圍是小于tokey(是否包括取決于第二個(gè)參數(shù))的所有key
SortedMap tailMap(Object fromKey):返回該Map的子Map,其key的范圍是大于fromkey(是否包括取決于第二個(gè)參數(shù))的所有key
class R implements Comparable { int count; public R(int count) { this.count = count; } public String toString() { return "R[count:" + count + "]"; } // 根據(jù)count來(lái)判斷兩個(gè)對(duì)象是否相等。 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; } // 根據(jù)count屬性值來(lái)判斷兩個(gè)對(duì)象的大小。 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) , "輕量級(jí)Java EE企業(yè)應(yīng)用實(shí)戰(zhàn)"); tm.put(new R(-5) , "瘋狂Java講義"); tm.put(new R(9) , "瘋狂Android講義"); System.out.println(tm); // 返回該TreeMap的第一個(gè)Entry對(duì)象 System.out.println(tm.firstEntry()); // 返回該TreeMap的最后一個(gè)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對(duì)。 System.out.println(tm.lowerEntry(new R(2))); // 返回該TreeMap的子TreeMap System.out.println(tm.subMap(new R(-1) , new R(4))); } }WeakHashMap
HashMap中的key保存的是實(shí)際對(duì)象的強(qiáng)引用,這意味著只要該HashMap對(duì)象不被銷(xiāo)毀,該HashMap的所有key所引用的對(duì)象就不會(huì)被垃圾回收,HashMap也不會(huì)自動(dòng)刪除這些key所對(duì)應(yīng)的key-value對(duì)
WeakHashMap中的key保存的是實(shí)際對(duì)象的弱引用,這意味著只要該WeakHashMap對(duì)象沒(méi)被其他強(qiáng)對(duì)象引用變量引用,則這些key所引用的對(duì)象可能被垃圾回收,就有可能會(huì)被垃圾回收機(jī)制回收對(duì)應(yīng)的Key-value,WeakHashMap也可能自動(dòng)刪除這些key所對(duì)應(yīng)的key-value對(duì)
public class WeakHashMapTest { public static void main(String[] args) { WeakHashMap whm = new WeakHashMap(); // 將WeakHashMap中添加三個(gè)key-value對(duì), // 三個(gè)key都是匿名字符串對(duì)象(沒(méi)有其他引用) whm.put(new String("南特") , new String("Nantes")); whm.put(new String("巴黎") , new String("Paris")); whm.put(new String("波爾多") , new String("Bordeaux")); //將 WeakHashMap中添加一個(gè)key-value對(duì), // 該key是一個(gè)系統(tǒng)緩存的字符串對(duì)象。 whm.put("馬賽" , new String("Marseille")); // ① // 輸出whm對(duì)象,將看到4個(gè)key-value對(duì)。 System.out.println(whm); // 通知系統(tǒng)立即進(jìn)行垃圾回收 System.gc(); System.runFinalization(); // 通常情況下,將只看到一個(gè)key-value對(duì)。 System.out.println(whm); } }
當(dāng)系統(tǒng)進(jìn)行垃圾回收時(shí),刪除了WeakHashMap對(duì)象的前三個(gè)key-value對(duì)。因?yàn)樘砑忧叭齻€(gè)key-value對(duì)時(shí),這三個(gè)key都是匿名的字符串對(duì)象,WeakHashMap只保留了對(duì)它們的弱引用,這樣垃圾回收時(shí)會(huì)自動(dòng)刪除這三個(gè)key-value對(duì)。第4個(gè)key-value對(duì)的key是一個(gè)字符串直接量(系統(tǒng)會(huì)自動(dòng)保留對(duì)該字符串對(duì)象的強(qiáng)引用),所以垃圾回收時(shí)不會(huì)回收它
IdentityHashMap實(shí)現(xiàn)類(lèi)IdentityHashMap的實(shí)現(xiàn)機(jī)制與HashMap基本相似,在IdentityHashMap中,判斷兩個(gè)key是否相等,是通過(guò)嚴(yán)格相等即(key1==key2)來(lái)判斷的,而HashMap是通過(guò)equals()方法和hashCode()這兩個(gè)方法來(lái)判斷key是否相等的。IdentityHashMap允許使用null作為key和value,不保證key-value對(duì)之間的順序,不保證它們的順序隨時(shí)間的推移保持不變
public class IdentityHashMapTest { public static void main(String[] args) { IdentityHashMap ihm = new IdentityHashMap(); // 下面兩行代碼將會(huì)向IdentityHashMap對(duì)象中添加兩個(gè)key-value對(duì) ihm.put(new String("勒布朗詹姆斯") , 23); ihm.put(new String("勒布朗詹姆斯") , 6); // 下面兩行代碼只會(huì)向IdentityHashMap對(duì)象中添加一個(gè)key-value對(duì) ihm.put("科比布萊恩特" , 8); ihm.put("科比布萊恩特" , 24); System.out.println(ihm); } }
前2個(gè)key-value對(duì)中的key是新創(chuàng)建的字符串對(duì)象,它們通過(guò)==比較不相等,所以IdentityHashMap會(huì)把它們當(dāng)成2個(gè)key來(lái)處理;后2個(gè)key-value對(duì)中的key都是字符串直接量,而且它們的字符序列完全相同,Java使用常量池來(lái)管理字符串直接量,所以它們通過(guò)==比較返回true,IdentityHashMap會(huì)認(rèn)為它們是同一個(gè)Key,因此只有一次可以添加成功
EnumMap實(shí)現(xiàn)類(lèi)EnumMap是一個(gè)與枚舉類(lèi)一起使用的Map實(shí)現(xiàn),EnumMap中的所有key都必須是單個(gè)枚舉類(lèi)的枚舉值。創(chuàng)建EnumMap時(shí)必須顯式或隱式指定它對(duì)應(yīng)的枚舉類(lèi)。EnumMap具有如下特征:
EnumMap在內(nèi)部以數(shù)組形式保存,所以這種實(shí)現(xiàn)形式非常緊湊、高效
EunmMap根據(jù)key的自然順序(即枚舉值在枚舉類(lèi)中的定義順序)來(lái)維護(hù)key-value對(duì)的順序。當(dāng)程序通過(guò)keySet()、entrySet()、values()等方法遍歷EnumMap時(shí)可以看到這種順序
EnumMap不允許使用null作為key,但允許使用null作為value。如果試圖使用null作為key時(shí)將拋出NullpointerException。如果只是查詢(xún)是否包含值為null的key,或只是刪除值為null的key,都不會(huì)拋出異常
enum NBA_Player { James,Westbrook,Curry,Harden } public class EnumMapTest { public static void main(String[] args) { // 創(chuàng)建EnumMap對(duì)象,該EnumMap的所有key都是Season枚舉類(lèi)的枚舉值 EnumMap enumMap = new EnumMap(NBA_Player.class); enumMap.put(NBA_Player.Westbrook, "俄克拉荷馬雷霆"); enumMap.put(NBA_Player.James, "克利夫蘭騎士"); System.out.println(enumMap); } }
創(chuàng)建EnumMap對(duì)象時(shí)指定它的key只能是NBA_Player枚舉類(lèi)的枚舉值。如果向該EnumMap中添加兩個(gè)key-value對(duì)后,這兩個(gè)key-value對(duì)將會(huì)以NBA_Player枚舉值的自然順序排序
各Map實(shí)現(xiàn)類(lèi)的性能分析HashMap和Hashtable的實(shí)現(xiàn)機(jī)制幾乎一樣,但由于Hashtable是一個(gè)古老的、線(xiàn)程安全的集合,因此HashMap通常比Hashtable要快
TreeMap比HashMap和Hashtable要慢(尤其在插入、刪除key-value對(duì)時(shí)更慢),因?yàn)門(mén)reeMap底層采用紅黑樹(shù)來(lái)管理key-value對(duì)(紅黑樹(shù)的每個(gè)節(jié)點(diǎn)就是一個(gè)key-value對(duì))
TreeMap中的key-value總是處于有序狀態(tài),無(wú)需專(zhuān)門(mén)進(jìn)行排序操作。當(dāng)TreeMap被填充后,就可以調(diào)用keySet(),取得由key組成的Set,然后使用toArray()方法生成key的數(shù)組,接下來(lái)使用Arrays的binarySearch()方法在已排序的數(shù)組中快速查詢(xún)對(duì)象
LinkedHashMap比HashMap慢一點(diǎn),因?yàn)樗枰S護(hù)鏈表來(lái)保持Map中key-value時(shí)的添加順序
IdentityHashMap性能沒(méi)有特別出色支持,采用與HashMap基本相似的實(shí)現(xiàn),只是它使用==而不是equals()方法來(lái)判斷元素相等
EnumMap性能最好,但它只能使用同一個(gè)枚舉類(lèi)的枚舉值作為key
對(duì)于一般的應(yīng)用場(chǎng)景,程序應(yīng)該多考慮使用HashMap,因?yàn)镠ashMap正是為快速查詢(xún)?cè)O(shè)計(jì)的(HashMap底層其實(shí)也是采用數(shù)組來(lái)存儲(chǔ)key-value對(duì))。但如果程序需要一個(gè)總是排好序的Map時(shí),則可以考慮使用TreeMap
HashSet和HashMap的性能選項(xiàng)對(duì)于HashSet及其子類(lèi)而言,它們采用hash算法來(lái)決定集合中元素的存儲(chǔ)位置,并通過(guò)hash算法來(lái)控制集合的大小;
對(duì)于HashMap、Hashtable及其子類(lèi)而言,它們采用hash算法來(lái)覺(jué)得Map中key的存儲(chǔ),并通過(guò)hash算法來(lái)增加key集合的大小
hash表里可以存儲(chǔ)元素的位置被稱(chēng)為“桶(bucket)”,在通常情況下,單個(gè)“桶”里存儲(chǔ)一個(gè)元素時(shí),此時(shí)擁有最好的性能:hash算法可以根據(jù)hashCode值計(jì)算出“桶”的存儲(chǔ)位置,接著從“桶”中取出元素。但hash表的狀態(tài)是open的:在發(fā)生“hash沖突”的情況下,單個(gè)桶會(huì)存儲(chǔ)多個(gè)元素,這些元素以鏈表形式存儲(chǔ),必須按順序搜索。如下圖所示是hash表保存各元素
因?yàn)镠ashSet和HashMap、Hashtable都使用hash算法來(lái)決定其元素(HashMap則只考慮key)的存儲(chǔ),因此HashSet、HashMap的hash表中包含如下屬性
容量(capacity):hash表中桶的數(shù)量
初始化容量(inital capacity):創(chuàng)建hash表時(shí)桶的數(shù)量。HashMap和HashSet都允許在構(gòu)造器中指定初始化容量
尺寸(size):當(dāng)前hash表中記錄的數(shù)量
負(fù)載因子(load factor):負(fù)載因子等于“size/capacity”。負(fù)載因子為0,表示空的hash表,0.5表示半滿(mǎn)的hash表,依次類(lèi)推。輕負(fù)載的hash表具有沖突少,適宜插入與查詢(xún)的特點(diǎn)(但是用Iterator迭代元素時(shí)比較慢)
除此之外,hash表里還有一個(gè)“負(fù)載極限”是一個(gè)0~1的數(shù)值,“負(fù)載極限”決定了hash表的最大填滿(mǎn)程序。
當(dāng)hash表中的負(fù)載因子達(dá)到指定的“負(fù)載極限”時(shí),hash表會(huì)自動(dòng)成倍地增加容量(桶的數(shù)量),并將原有的對(duì)象重新分配,嵌入新的桶內(nèi),這稱(chēng)為rehashing
HashSet和HashMap、Hashtable的構(gòu)造器允許指定一個(gè)負(fù)載極限,HashSet和HashMap、Hashtable默認(rèn)的“負(fù)載極限”為0.75,這表明當(dāng)該hash表的3/4已經(jīng)被填滿(mǎn)時(shí),hash表會(huì)發(fā)生rehashing
“負(fù)載極限”的默認(rèn)值(0.75)是時(shí)間和空間成本上的一種折中:較高的“負(fù)載極限”可以降低hash表所占用的內(nèi)存空間,但會(huì)增加查詢(xún)數(shù)據(jù)和時(shí)間的開(kāi)銷(xiāo),而查詢(xún)是最頻繁的操作(HashMap的get()和put()方法都要用到查詢(xún));
較低的“負(fù)載極限”會(huì)提高查詢(xún)數(shù)據(jù)的性能,但會(huì)增加hash表所占用的內(nèi)存開(kāi)銷(xiāo)。
如果開(kāi)始就知道HashSet和HashMap、Hashtable會(huì)保存很多記錄,則可以在創(chuàng)建時(shí)就使用較大的初始化容量,如果初始化容量始終大于HashSet、Hashtable和HashMap所包含的最大記錄數(shù)除以“負(fù)載極限”,就不會(huì)發(fā)生rehashing。使用足夠大的初始化容量創(chuàng)建HashSet和HashMap、Hashtable時(shí),可以更高效地增加記錄,但將初始化容量設(shè)置太高會(huì)浪費(fèi)空間,所以不要講初始化容量設(shè)置過(guò)高
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/66404.html
摘要:通過(guò)找到值此方法相當(dāng)于集合中的方法返回此屬性列表中的鍵集,其中該鍵及其對(duì)應(yīng)值是字符串此方法相當(dāng)于集合中的方法創(chuàng)建集合對(duì)象使用往集合中添加數(shù)據(jù)趙麗穎迪麗熱巴古力娜扎使用把集合中的鍵取出存儲(chǔ)到一個(gè)集合中遍歷集合取出集合的每一個(gè)鍵使用方法通過(guò)獲取 package com.itheima.demo07.Prop; import java.io.FileOutputStream;import j...
摘要:集合的特點(diǎn)集合的特點(diǎn)類(lèi)介紹類(lèi)表示了一個(gè)持久的屬性集??杀4嬖诹髦谢驈牧髦屑虞d。屬性列表中每個(gè)鍵及其對(duì)應(yīng)值都是一個(gè)字符串特點(diǎn)的子類(lèi),集合中的方法都可以用。該集合沒(méi)有泛型。鍵值可以存儲(chǔ)到集合中,也可以存儲(chǔ)到持久化的設(shè)備硬盤(pán)盤(pán)光盤(pán)上。 01Properties集合的特點(diǎn) * A: Properties集合的特點(diǎn) * a: Properties類(lèi)介紹 * Propert...
摘要:但它融合了和的功能。支持對(duì)隨機(jī)訪(fǎng)問(wèn)文件的讀取和寫(xiě)入。的概述和作為集合的使用了解的概述類(lèi)表示了一個(gè)持久的屬性集??杀4嬖诹髦谢驈牧髦屑虞d。屬性列表中每個(gè)鍵及其對(duì)應(yīng)值都是一個(gè)字符串。 1_序列流(了解) 1.什么是序列流 序列流可以把多個(gè)字節(jié)輸入流整合成一個(gè), 從序列流中讀取數(shù)據(jù)時(shí), 將從被整合的第一個(gè)流開(kāi)始讀, 讀完一個(gè)之后繼續(xù)讀第二個(gè), 以此類(lèi)推. 2.使用方式 整合兩個(gè): S...
摘要:一配置屬性詳解可以在各式各樣不同環(huán)境下工作而設(shè)計(jì)的因此存在著大量的配置參數(shù)。以簡(jiǎn)便操作,多數(shù)配置參數(shù)都有默認(rèn)的配置值也是我們?nèi)粘J褂玫谋仨毱贰? Hibernate (開(kāi)放源代碼的對(duì)象關(guān)系映射框架) Hibernate是一個(gè)開(kāi)放源代碼的對(duì)象關(guān)系映射框架,它對(duì)JDBC進(jìn)行了非常輕量級(jí)的對(duì)象封裝, 它將POJO與數(shù)據(jù)庫(kù)表建立映射關(guān)系,是一個(gè)全自動(dòng)的orm框架,hibernat...
摘要:簡(jiǎn)單來(lái)說(shuō),是一個(gè)輕量級(jí)的控制反轉(zhuǎn)和面向切面的容器框架。變成的支持提供面向切面編程,可以方便的實(shí)現(xiàn)對(duì)程序進(jìn)行權(quán)限攔截,運(yùn)行監(jiān)控等功能。用于反射創(chuàng)建對(duì)象,默認(rèn)情況下調(diào)用無(wú)參構(gòu)造函數(shù)。指定對(duì)象的作用范圍。 1.Spring介紹 1.1 Spring概述 Spring是一個(gè)開(kāi)源框架,Spring是于2003 年興起的一個(gè)輕量級(jí)的Java 開(kāi)發(fā)框架,由Rod Johnson 在其著作Expert...
閱讀 1773·2021-11-12 10:36
閱讀 1675·2021-11-12 10:36
閱讀 3509·2021-11-02 14:46
閱讀 3907·2019-08-30 15:56
閱讀 3729·2019-08-30 15:55
閱讀 1528·2019-08-30 15:44
閱讀 1111·2019-08-30 14:00
閱讀 2781·2019-08-29 18:41