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