-
Map
Map用于儲存具有映射關系的資料,是以Map集合裡儲存着兩組值,一組值用于儲存Map裡的key,另一組值用于儲存Map裡的value,key和value都可以是任何引用類型的資料。Map的key不容許重複,即同一個Map對象的任何兩個key通過equals方法比較總是傳回false。
key和value之間存在單向一對一關系,即通過指定的key,總能找到唯一的、确定的value。從Map中取出資料時,隻要給出指定的key,就可以取出對應的value。
如果把Map裡的所有key放在一起看,它們就是一個Set集合,實際上Map确實包含一個keySet()方法,用于傳回Map所有key組成的Set集合。如下:
public class Test {
public static void main(String[] args){
Map<String, String> mapVal = new HashMap<String, String>();
mapVal.put("spring", "春");
mapVal.put("summer", "夏");
mapVal.put("autumn", "秋");
mapVal.put("winter", "冬");
//擷取mapVal集合的所有key值
Set<String> set = mapVal.keySet();
Iterator<String> it = set.iterator();
while(it.hasNext()){
String season = it.next();
System.out.println(season);
}
}
}
不僅如此,Map裡key集合和Set集合裡元素的存儲形式也很像,Map子類和Set子類在名字上也驚人的相似:如Set接口下有HashSet、LinkedHashSet、SortedSet(接口)、TreeSet、EnumSet等實作類和子接口,而Map接口下則有HashMap、LinkedHashMap、SortedMap(接口)、TreeMap、EnumMap等實作類和子接口。正如它們名字所暗示的,Map的這些實作類和子接口中key集存儲形式和對應Set集合中元素的存儲形式完全相同。
如果把Map所有value放在一起看,它們又非常類似于一個List:元素與元素之間可以重複,每個元素可以根據索引來查找,隻是map中的索引不再使用整數值,而是以另一個對象做為索引。如果需要從List集合中取元素,需要提供該元素的數字索引;如果需要從Map中取出元素,需要提供該元素的key索引。是以,Map有時也被稱為字典,或關聯數組。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(Object 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對。
- void putAll(Map m); //将指定Map中的key-value對複制到本Map中。
- Object remove(Object key); //删除指定key所對應的key-value對,傳回被删除key所關聯的value,如果key不存在,傳回nul
- 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(V value); //設定該Entry裡包含的value值,并傳回新設定的value值。
我們可以把Map了解成一個特殊的Set,隻是該Set裡包含的集合元素是Entry對象,而不是普通對象。
如下為Entry示例:
public class Test {
public static void main(String[] args){
Map<String, String> mapVal = new HashMap<String, String>();
mapVal.put("spring", "春");
mapVal.put("summer", "夏");
mapVal.put("autumn", "秋");
mapVal.put("winter", "冬");
Set<Entry<String, String>> entrySet = mapVal.entrySet();
Iterator<Entry<String, String>> iterator = entrySet.iterator();
while(iterator.hasNext()){
Entry<String, String> next = iterator.next();
String key = next.getKey();
String value = next.getValue();
System.out.println("key:"+ key +"-------value:" + value);
}
}
}
-
HashMap和Hashtable實作類
HashMap和Hashtable都是Map接口的典型實作類,他們之間的關系完全類似于ArrayList和Vector的關系:Hashtable是一個古老的Map實作類,它從JDK1.0起就已經出現了,當它出現時,Java沒有提供Map接口,是以它包含了兩個繁瑣的方法:elements()(類似于Map接口定義的values()方法)和keys(類似于Map接口定義的keySet()方法),現在很少使用這兩個方法。
HashMap和Hashtable的兩點典型差別:
Hashtable是一個線程安全的Map實作,但HashMap是線程不安全的實作,是以HashMap比Hashtable性能要高一點;但如果有多條線程通路同一個Map對象時,使用Hashtable實作類會更好。
Hashtable不容許使用null作為key和value,如果試圖把null放進Hashtable中,将會引發NullPointerException異常;但HashMap可以使用null做為key和value。
注意:與Vector類似,盡量少用Hashtable實作類,即使需要建立線程安全的Map實作類,也可以通過Collections工具類把HashMap變成線程安全的,無須使用Hashtable實作類。
為了成功地在HashMap、Hashtable中存儲、擷取對象,用作key的對象必須實作hashCode方法和equals方法。
與HashSet不能保證元素的順序一樣,HashMap和Hashtable也不能保證key-value對的順序。類似于HashSet的是,HashMap、Hashtable判斷兩個key相等的标準也是:兩個key通過equals方法比較傳回true,兩個key的hashCode值也相等。
除此之外,HashMap、Hashtable中還包含一個containsValue方法用于判斷是否包含指定的value,那麼HashMap、Hashtable如何判斷兩個value相等呢?HashMap、Hashtable判斷兩個value相等的标準更簡單:隻要兩個對象通過equals比較傳回true即可。
-
LinkedHashMap類
HashMap有一個子類:LinkedHashMap;LinkedHashMap也使用雙向連結清單來維護key-value對的次序,該連結清單定義了疊代順序,該疊代順序與key-value對的插入順序保持一緻。LinkedHashMap可以避免需要對HashMap、Hashtable裡的key-value對進行排序(隻要插入key-value對時保持順序即可)。同時又避免使用TreeMap所增加的成本。
LinkedHashMap需要維護元素的插入順序,是以性能略低于HashMap的性能,但在疊代通路Map裡的全部元素時将有很好的性能,因為它以連結清單來維護内部順序。
public class Test {
public static void main(String[] args){
LinkedHashMap<String, String> mapVal = new LinkedHashMap<String, String>();
mapVal.put("spring", "春");
mapVal.put("summer", "夏");
mapVal.put("autumn", "秋");
mapVal.put("winter", "冬");
System.out.println(mapVal);
for(String str : mapVal.keySet()){
System.out.println("key:" + str);
System.out.println("value:" + mapVal.get(str));
}
}
}
-
Properties類
Properties類是Hashtable類的子類,正如它的名字所暗示的,該檔案在處理屬性檔案。Properties類可以把Map對象和屬性檔案關聯起來,進而可以把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 setProperty(String key, String value); //設定屬性值,類似Hashtable的put方法。
- void load(InputStream inStream); //從屬性檔案(以輸出流表示)中加載屬性名=屬性值,把加載到的屬性名=屬性值對追加到Properties裡(由于Properties是Hashtable的之類,它不保證key-value對之間的次序)。
- void store(OutputStream out, String comments); //将Properties中的key-value對寫入指定屬性檔案(以輸出流表示),comments是要寫的注解。
如下代碼所示:
public class Test {
public static void main(String[] args){
Properties readProperties = new Properties(); //用來寫的Properties對象
readProperties.setProperty("username", "zhangsan");
readProperties.setProperty("password", "123456");
Properties writeProperties = new Properties(); //用來讀的Properties對象
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
try {
//1.1通過類裝載器擷取要存儲的路徑
String path = Test.class.getResource("/").getPath();
path = path + "config.properties";
System.out.println(path);
fileOutputStream = new FileOutputStream(new File(path));
//1.2将配置檔案資訊寫到硬碟上
readProperties.store(fileOutputStream, "This is config with database!");
//2.1讀取硬碟上的配置檔案
fileInputStream = new FileInputStream(new File(path));
writeProperties.load(fileInputStream);
String username = writeProperties.getProperty("username");
String username2 = writeProperties.getProperty("username2" , "沒有找到username2的key");
//列印結果"sername:zhangsan"
System.out.println("username:" + username);
//列印結果"username2:沒有找到username2的key"
System.out.println("username2:" + username2);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(fileOutputStream != null){
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
-
SortedMap接口和TreeMap實作類
正如Set接口派生出了SortedSet子接口,SortedSet接口有一個TreeSet實作類,Map接口也派生了一個SortedMap子接口,SortedMap也有一個TreeMap實作類。
與TreeSet類似的是,TreeMap也是基于紅黑樹對TreeMap中所有key進行排序,進而保證TreeMap中所有key-value對處于有序狀态。TreeMap也有兩種排序方式:
自然排序:TreeMap的所有key必須實作那Comparable接口,而且所有key應該是同一個類的對象,否則将會抛出ClassCaseException。
定制排序:建立TreeMap時,傳入一個Comparator對象,該對象負責對TreeMap中所有key進行排序。采用定制排序時不要求Map的key實作Comparable接口。
*可以參考TreeSet的代碼示範。
修飾符和類型 | 方法和描述 |
---|---|
| 傳回大于或等于給定鍵相關聯的與最小鍵 - 值映射,或者 如果不存在這樣的鍵。 |
| 傳回大于或等于給定鍵的最小鍵,或者 |
| 從此映射中删除所有映射。 |
| 傳回此 執行個體的淺表副本。 |
| 傳回用于對此映射中的鍵進行排序的比較器,或者 此映射使用其鍵的自然排序。 |
| 如果此映射包含指定鍵的映射,則傳回。 |
| 傳回 如果此映射将一個或多個鍵映射到指定值。 |
| 此映射中包含的鍵的逆序視圖。 |
| 傳回此映射中包含的映射的逆序視圖。 |
| 此映射中包含的映射的視圖。 |
| 傳回與此地圖中最小鍵相關的鍵值映射,或者 地圖為空。 |
| 傳回此地圖中目前第一個(最低)的鍵。 |
| 傳回與最大鍵小于或等于給定鍵相關聯的鍵 - 值映射,如果不存在這樣的鍵,則傳回null。 |
| 傳回小于或等于給定鍵的最大鍵,如果不存在這樣的鍵傳回null。 |
| 對此映射中的每個條目執行給定操作,直到處理完所有條目或操作抛出異常為止。 |
| 傳回指定鍵映射到的值,或者 此映射不包含鍵的映射。 |
| 傳回此映射的關鍵字嚴格小于的部分的視圖 。 |
| 傳回此映射關鍵字小于(或等于,如果 為真)的部分的視圖 |
| 傳回與最小鍵相關的鍵 - 值映射嚴格大于給定鍵,或者 |
| 傳回嚴格大于給定鍵的最小鍵,或者 |
| 此映射中包含的鍵的視圖。 |
| 傳回與此地圖中最大鍵關聯的鍵值映射,或者 映射為空。 |
| 傳回此地圖中目前最後一個(最高)的鍵。 |
| 傳回與最大鍵相關的鍵 - 值映射嚴格小于給定鍵,或者 如果沒有這樣的鍵。 |
| 傳回最大的密鑰嚴格小于給定的密鑰,或者 如果沒有這樣的密鑰。 |
| |
| 移除并傳回與此地圖中的最小鍵相關聯的鍵值映射,或者 |
| 移除并傳回與此地圖中最大鍵關聯的鍵值映射,或者 |
| 将指定的值與此映射中指定的鍵關聯。 |
| 将指定地圖中的所有映射複制到此地圖。 |
| 如果存在,則從此TreeMap中移除此鍵的映射。 |
| 僅當指定鍵的條目映射到某個值時才替換該條目。 |
| 僅當目前映射到指定值時才替換指定鍵的條目。 |
| 用對該條目調用給定函數的結果替換每個條目的值,直到處理完所有條目或者該函數抛出異常。 |
| 傳回此映射中鍵值映射的數量。 |
| 傳回此鍵映射範圍從0 到的部分視圖 |
| 傳回此映射部分的視圖,其鍵範圍從 (包含)到 獨占。 |
| 傳回此映射的鍵大于或等于的部分的視圖 |
| 傳回此映射關鍵字大于(或等于,如果 |
| 此映射中包含的值的視圖。 |
-
WeakHashMap實作類
WeakHashMap與HashMap的用法基本相似。但與HashMap的差別在于,HashMap的key保留對象的強引用,這意味着隻要該HashMap對象不被銷毀,該HashMap對象所有key所引用的對象不會被垃圾回收,HashMap也不會自動删除這些key所對應的key-value對象;但WeakHashMap的key隻保留對實際對象的弱引用,這意味着當垃圾回收了該key所對應的實際對象後,WeakHashMap會自動删除該key對應的key-value對。
public class Test {
public static void main(String[] args){
WeakHashMap<String, String> map = new WeakHashMap<String, String>();
//将WeakHashMap中添加三個key-value對,
//三個key都是匿名字元串對象(沒有其他引用)
map.put(new String("國文"), new String("優"));
map.put(new String("數學"), new String("良"));
map.put(new String("英語"), new String("中"));
//将WeakHashMap中添加一個key-value對,
//該key是一個系統緩存的字元串對象。
map.put("java", new String("不及格"));
//輸出map對象,将看到4個key-value對{java=不及格, 數學=良, 英語=中, 國文=優}
System.out.println(map);
//通知系統立即進行垃圾回收
System.gc();
System.runFinalization();
//通常情況下,将隻看到一個key-value對{java=不及格}
System.out.println(map);
}
}
從上面運作結果可以看出,當系統進行垃圾回收時,删除了WeakHashMap對象的前三個key-value對。這是因為添加前三個key-value對時,這三個key都是匿名字元串對象,隻有WeakHashMap保留了對它們的弱引用。WeakHashMap對象中的第四組key-value對的key是一個字元串的直接量,系統會緩沖這個字元串直接量(即系統保留了對該字元串對象的強引用),是以垃圾回收時不會回收它。
-
IdentityHashMap實作類
IdentityHashMap實作類的實作機制與HashMap基本相似,但它在處理兩個key相等時,比較獨特:在IdentityHashMap中,當且僅當兩個key嚴格相等時(key1 = key2)時,IdentityHashMap才認為兩個key相等,對于普通HashMap而言,隻要key1和key2通過equals比較傳回true,且它們的hashCode值相等即可。
IdentityHashMap提供了與HashMap基本相似的方法,也允許使用null做為key和value。與HashMap類似的是,IdentityHashMap不保證任何key-value對之間的順序,更不能保證它們的順序随時間的推移保持不變。
public class Test {
public static void main(String[] args){
IdentityHashMap<String, String> map = new IdentityHashMap<String, String>();
//下面兩行代碼會向map中添加兩條key-value對
map.put(new String("國文"), "99");
map.put(new String("國文"), "100");
//下面兩行代碼會向map中添加一條key-value對
map.put("java", "89");
map.put("java", "69");
//列印結果為{java=69, 國文=100, 國文=99}
System.out.println(map);
}
}
-
EnumMap實作類
EnumMap是一個與枚舉類一起使用的Map實作,EnumMap中所有key都必須是單個枚舉類的枚舉值。建立EnumMap時必須顯示或隐式指定它對應的枚舉類。
EnumMap不允許使用null作為key值,但容許使用null值做為value。如果試圖使用null做為key将抛出NullPointerException異常。如果僅僅隻是查詢是否包含值為null的key,或者僅僅隻是使用删除值為null的key,都不會抛出異常。
enum Season{
SPRING,SUMMER,AUTUMN,WINTER
}
public class Test {
public static void main(String[] args){
EnumMap<Season, String> map = new EnumMap<Season, String>(Season.class);
//列印結果為{}
System.out.println(map);
map.put(Season.SPRING, "春");
map.put(Season.SUMMER, "夏");
map.put(Season.AUTUMN, "秋");
map.put(Season.WINTER, "冬");
//列印結果為{SPRING=春, SUMMER=夏, AUTUMN=秋, WINTER=冬}
System.out.println(map);
}
}
上面程式中建立了一個EnumMap對象,建立該EnumMap對象時指定它的key隻能是Season枚舉類的枚舉值。如果向該EnumMap中添加四個key-value對後,這四個key-value對将會以Season枚舉值的自然順序排序。
對于Map的常用實作類而言,HashMap和Hashtable的效率大緻相同,因為它們的實作機制幾乎完全一樣,但HashMap通常比Hashtable要快一點,因為Hashtable額外實作同步操作。
TreeMap通常比HashMap、Hashtable要慢(尤其在插入、删除key-value對的時候更慢),因為TreeMap需要額外的紅黑樹操作來維護key之間的次序。但使用TreeMap有一個好處:TreeMap中的key-value對總是處于有序狀态,無須專門進行排序操作。
作者:郭耀華
出處:http://www.guoyaohua.com
微信:guoyaohua167
本文版權歸作者和部落格園所有,歡迎轉載,轉載請标明出處。
【如果你覺得本文還不錯,對你的學習帶來了些許幫助,請幫忙點選右下角的推薦】