1. 程式人生 > 其它 >關於Java中的Map的淺拷貝和深拷貝問題

關於Java中的Map的淺拷貝和深拷貝問題

技術標籤:使用筆記

關於Java中的Map的淺拷貝和深拷貝問題

發生背景

  • 生產列印的log會有圖片的Base64碼 這並不是我們實際日誌中需要關心的東西
  • 想定的解決案是在切面列印日誌類中刪除掉列印log的欄位

使用過程

  • 根據方法的引數做區分 定位到對應的引數是 刪除掉引數中的圖片欄位

    • 程式碼
    if (args.length == 1 && args[0] instanceof Map){
        Map<String,Object> argMap = (Map)args[0];
        argMap.remove("picture");
        log.
    info("{}.{} : 介面呼叫開始--> 請求引數:{} ", method.getDeclaringClass().getName(), method.getName(), JSONObject.toJSONString(argMap, SerializerFeature.WriteMapNullValue)); } else { log.info("{}.{} : 介面呼叫開始--> 請求引數:{} ", method.getDeclaringClass().getName(), method.getName
    (), JSONObject.toJSONString(args, SerializerFeature.WriteMapNullValue)); }

產生問題

  • 進入真正呼叫的方法的時候,出現引數校驗問題,返回異常資訊請求的必要引數為空

問題分析

  • 真正獲取的是map的深拷貝資訊(物件地址)

  • 刪除map中的物件,會把引數中的物件一起刪除掉

在這裡插入圖片描述

問題引申

  1. Java中的淺拷貝和深拷貝問題
    • 什麼時候應該使用淺拷貝
    • 什麼時候應該使用深拷貝
  2. 使用淺拷貝就一定沒有對應問題了嗎

深入研究

  • 淺拷貝:只複製物件的引用,兩個引用指向同一個物件,在記憶體中佔用同一塊記憶體,被複制物件的所有變數都含有與原來的物件相同的值,而所有的對其他物件的引用仍然指向原來的物件,換言之,淺拷貝僅僅複製所考慮的物件,而不復制它所引用的物件。

  • 深拷貝:被複制物件的所有變數都含有與原來的物件相同的值,除去那些引用其他物件的變數,那些引用其他物件的變數將指向被複制過的新物件,而不再是原有的那些被引用的物件,換言之,深拷貝把要複製的物件所引用的物件都複製了一遍。

  • 程式碼

    • 淺拷貝

          public static void main(String[] args) {
              Map<String, String> map = new HashMap<>();
              map.put("name", "jack");
              Map<String, String> copyMap = new HashMap<>();
              // 淺拷貝 使用=賦值
              copyMap = map;
              map.remove("name");
              System.out.println("map : " + map);
              System.out.println("copyMap : " + copyMap);
          }
      
      ======> 執行結果
          map : {}
      copyMap : {}
      
    • 深拷貝

          public static void main(String[] args) {
              Map<String, String> map = new HashMap<>();
              map.put("name", "jack");
              Map<String, String> copyMap = new HashMap<>();
              // 深拷貝 使用putAll
              // 或者使用構造器 一樣可以實現深拷貝
              // Map<String, String> copyMap = new HashMap<>(map);
              copyMap.putAll(map);
              map.remove("name");
              System.out.println("map : " + map);
              System.out.println("copyMap : " + copyMap);
          }
          
      ======> 執行結果
      	map : {}
      copyMap : {name=jack}
      
  • 總結

    • 實現淺拷貝的方式有1種:=
    • 實現深拷貝有兩種:Map.putAll()和構造器
      • 使用=進行賦值的方法,並不是真正意義上的拷貝,Map物件B只是對Map物件A進行了引用,當Map物件A中的內容發生變化時,Map物件B也會發生變化;
      • 使用Map呼叫putAll()方法才是真正意義上的拷貝。