Java - Collection(二)

By sunwc 2023-03-29 Java

JDK 1.8 Collection 框架 - interface Map 架構

  • interface Map:雙列資料,儲存key-value對的資料

    • Map 中的 key:無序的、不可重複的,使用 Set 儲存所有的 key
    • Map 中的 value:無序的、可重複的,使用 Collection 儲存所有的 value
    • 一個鍵值對:Key-value構成了一個 Entry 物件
    • Map 中的 entry:無序的、不可重複的,使用 Set 儲存所有的 entry

    • HashMap:作為 interface Map 的主要實現類;執行緒不安全的,效率高;可以儲存null的key和value;底層使用 陣列+鏈結串列+紅黑樹

      • HashMap 的 key 所在類別要覆寫 equals() 和 hashCode()
      • HashMap 的 value 所在類別要覆寫 equals()
      • HashMap 的底層實現原理:以 JDK 7 為例說明:
        1. HashMap map = new HashMap(): 在實例化以後,底層創建了長度是16的一維陣列Entry[] table
        ...可能已經執行過多次put()...
        2. map.put(key1,value1): 首先,調用 key1 所在類別的 hashCode() 計算 key 哈希值,此哈希值經過計算後得到在 Entry 陣列中的存放位置:
        
            如果此位置上的資料為空,此時 key1-value1 新增成功 => 情況1
            如果此位置上的資料不為空,(意味著此位置上存在一個或多個資料(以鏈結串列形式存在)),比較 key1 和已經存在的一個或多個資料的哈希值:
        
                如果 key1 的哈希值與已經存在的資料的哈希值都不同,此時 key1-value1 新增成功 => 情況2
                如果 key1 的哈希值和已經存在的某一個資料(key2-value2)的哈希值相同,繼續比較:調用 key1 所在類別的 equals(key2):
        
                    如果 equals() 回傳 false:此時 key1-value1 新增成功 => 情況3
                    如果 equals() 回傳 true:使用 value1 替換 value2  
        
        補充:關於情況2、情況3:此時 key1-value1 和原來的資料以鏈結串列的方式儲存
        
        3. 在不斷地新增的過程中,會涉及到擴容問題,默認擴容方式,擴容為原來的2倍,並將原有的資料複製過來
        
      • HashMap 遍歷:
        • 遍歷所有的 key 集: keySet()
        • 遍歷所有的 value 集: values()
        • 遍歷所有的 key-value: entrySet()
      • HashMap 常用方法:
        • 新增:put(Object key, Object value)
        • 刪除:remove(Object key)
        • 修改:put(Object key, Object value)
        • 查詢:get(Object key)
        • 長度:size()
        • 遍歷:keySet()/ values()/ entrySet()

      • LinkedHashMap:作為 HashMap 的子類;保證在遍歷map元素時,可以按照新增的順序實現遍歷
        • 在原有的 HashMap 底層基礎上,每個元素還維護了兩個reference,紀錄資料的前一個與後一個元素的位置;對於頻繁的遍歷操作,LinkedHashMap 效率高於 HashMap

    • TreeMap:可以按照新增元素的key進行自然排序 或 定制排序
      • 底層結構是紅黑樹

    • Hashtable:作為 interface Map 的古老實現類;執行緒安全,效率低;不能儲存null的key和value


      • Properties:作為 Hashtable 的子類;常用來處理配置文件;key和value都是String類別
      /**
      * @author sunwc
      * @create 2023-03-29 下午 02:12
      */
      public class PropertiesTest {
      
          @Test
          public void propertiesTest()  {
      
              Properties properties = new Properties();
      
              FileInputStream fis = null;
              try {
                  // 方式一、
      //            fis = new FileInputStream(System.getProperty("user.dir") + "\\jdbc.properties");
      
                  // 方式二、
                  File file = new File("jdbc.properties");
                  fis = new FileInputStream(file.getAbsolutePath());
      
                  // 加載流對應文件
                  properties.load(fis);
      
                  String name = properties.getProperty("name");
                  String password = properties.getProperty("password");
                  System.out.println("name="+name+",password="+password);
      
              } catch (FileNotFoundException e) {
                  e.printStackTrace();
              } catch (IOException e) {
                  e.printStackTrace();
              } finally {
      
                  try {
                      if (fis != null) {
                          fis.close();
                      }
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
          }
      }
      

      輸出結果:

      name=ching,password=ching123