1. 程式人生 > >Java中的集合Map、HashMap、Hashtable、Properties、SortedMap、TreeMap、WeakHashMap、IdentityHashMap、EnumMap(五)

Java中的集合Map、HashMap、Hashtable、Properties、SortedMap、TreeMap、WeakHashMap、IdentityHashMap、EnumMap(五)

我們 obj ack ext.get 好處 output get () 硬盤

  • 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接口中定義了如下常用方法:

  1. void clear();  //刪除該Map對象中所有key-value對。
  2. boolean containsKey(Object key); //查詢Map中是否包含指定key,如果包含則返回true。
  3. boolean containsValue(Object value); //查詢Map中是否包含一個或多個value,如果包含則返回true。
  4. Set entrySet(); //返回Map中所包含的key-value對所組成的Set集合,每個集合元素都是Map.Entry(Entry是Map的內部類)對象。
  5. Object get(Object key); //返回指定key所對應的value,如果此Map不包含該key,則返回null。
  6. boolean isEmpty(); //查詢該Map集合是否為空(即不包含任何key-value對),如果為空則返回true。
  7. Set keySet(); //返回該Map中所有key所組成的Set集合。
  8. Object put(Object key, Object value); //添加一個key-value對,如果當前Map中已有一個與key相等的key-value對,則新的key-value對會覆蓋原來的key-value對。
  9. void putAll(Map m); //將指定Map中的key-value對復制到本Map中。
  10. Object remove(Object key);   //刪除指定key所對應的key-value對,返回被刪除key所關聯的value,如果key不存在,返回nul
  11. int size(); //返回該Map裏的key-value對的個數。
  12. Collection values(); //返回該Map裏所有value組成的Collection。

  Map中包含一個內部類:Entry。該類封裝了一個key-value對,Entry包含三個方法:

    1. Object getKey();  //返回該Entry裏包含的key值。
    2. Object getValue(); //返回該Entry裏包含的value值。
    3. 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實現類

  HashMapHashtable都是Map接口的典型實現類,他們之間的關系完全類似於ArrayList和Vector的關系:Hashtable是一個古老的Map實現類,它從JDK1.0起就已經出現了,當它出現時,Java沒有提供Map接口,所以它包含了兩個繁瑣的方法:elements()(類似於Map接口定義的values()方法)和keys(類似於Map接口定義的keySet()方法),現在很少使用這兩個方法。

  HashMap和Hashtable的兩點典型區別

    Hashtable是一個線程安全的Map實現,但HashMap是線程不安全的實現,所以HashMapHashtable性能要高一點;但如果有多條線程訪問同一個Map對象時,使用Hashtable實現類會更好。

    Hashtable不容許使用null作為key和value,如果試圖把null放進Hashtable中,將會引發NullPointerException異常;但HashMap可以使用null做為key和value。

  註意:與Vector類似,盡量少用Hashtable實現類,即使需要創建線程安全的Map實現類,也可以通過Collections工具類把HashMap變成線程安全的,無須使用Hashtable實現類。

    為了成功地在HashMapHashtable中存儲、獲取對象,用作key的對象必須實現hashCode方法和equals方法。

    與HashSet不能保證元素的順序一樣,HashMapHashtable也不能保證key-value對的順序。類似於HashSet的是,HashMap、Hashtable判斷兩個key相等的標準也是:兩個key通過equals方法比較返回true,兩個key的   hashCode值也相等。

    除此之外,HashMapHashtable中還包含一個containsValue方法用於判斷是否包含指定的value,那麽HashMap、Hashtable如何判斷兩個value相等呢?HashMap、Hashtable判斷兩個value相等的標準更簡單:只要兩個對象通過equals比較返回true即可。

  • LinkedHashMap類  

  HashMap有一個子類:LinkedHashMap;LinkedHashMap也使用雙向鏈表來維護key-value對的次序,該鏈表定義了叠代順序,該叠代順序與key-value對的插入順序保持一致。LinkedHashMap可以避免需要對HashMapHashtable裏的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值。

    1. String getProperty(String key); //獲取properties中指定屬性名對應的屬性值,類似於Map的get(Object key)方法。
    2. String getProperty(String key, String defaultValue); //該方法與前一個方法基本相似,該方法多個功能,如果Properties中不存在指定key時,該方法返回默認值。
    3. Object setProperty(String key, String value);   //設置屬性值,類似Hashtable的put方法。
    4. void load(InputStream inStream); //從屬性文件(以輸出流表示)中加載屬性名=屬性值,把加載到的屬性名=屬性值對追加到Properties裏(由於Properties是Hashtable的之類,它不保證key-value對之間的次序)。
    5. 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的代碼演示。

  • WeakHashMap實現類

  WeakHashMapHashMap的用法基本相似。但與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的常用實現類而言,HashMapHashtable的效率大致相同,因為它們的實現機制幾乎完全一樣,但HashMap通常比Hashtable要快一點,因為Hashtable額外實現同步操作。

  TreeMap通常比HashMap、Hashtable要慢(尤其在插入、刪除key-value對的時候更慢),因為TreeMap需要額外的紅黑樹操作來維護key之間的次序。但使用TreeMap有一個好處:TreeMap中的key-value對總是處於有序狀態,無須專門進行排序操作。  

         

    

Java中的集合Map、HashMap、Hashtable、Properties、SortedMap、TreeMap、WeakHashMap、IdentityHashMap、EnumMap(五)