深入Java深淺拷貝、immutable、unmodifiable

jopen 9年前發布 | 7K 次閱讀 Java開發 Java

  • 建議:函數調用的時候,調用方傳給被調用方的參數,如果在調用之后還會被修改,那么調用方應該給被調用方傳一個當時的拷貝,深拷貝,否則:

    • 可能被調用方是異步執行的,如果調用函數之后,參數發生了修改,那么被調用方執行的時候,看到的就是被修改之后的數據,這將導致嚴重、隱蔽、非必現的BUG,而這種BUG是最讓人頭疼的
    • 可能被調用方會修改傳入的參數,這就導致函數執行完畢之后,調用方看到的數據發生了非預期的變化,這同樣會導致嚴重、隱蔽的BUG
    • </ul> </li>

    • 深拷貝:這里需要弄清楚深淺拷貝的區別,用“=”號給非基本類型賦值,均是淺拷貝,例如List,以下代碼就是淺拷貝:
    • </ul>

       List<Integer> list1 = new ArrayList<>();
          list1.add(1);
          List<Integer> list2 = list1;
          list1.add(2);

      代碼執行完畢之后,list2將包含整數1和2。
      而以下代碼則是深拷貝:

          List<Integer> list1 = new ArrayList<>();
          list1.add(1); List<Integer> list2 = new ArrayList<>(list1);
          list1.add(2);

      代碼執行完畢之后,list2將只包含整數1,不包含整數2。

      • Immutable對象:上述情形如果遇到immutable對象,即不可變對象,其實是不需要深拷貝的(不僅不需要,還應該杜絕拷貝,因為純屬浪費)。但是前提是對象是真正的immutable。反面例子為:
      • </ul>

            public class NonStrictlyImmutable {
                private final List<Integer> mList = new ArrayList<>();

            public List<Integer> getList() {
                return mList;
            }
        }</pre>mList成員設置為了private final,NonStrictlyImmutable對象實例化完成后mList所引用的實際對象也不可再被改變,然而mList這個List的元素確是可以改變的,nonStrictlyImmutable.getList().add(1)并不會報編譯錯誤,而這一行代碼卻實實在在改變了nonStrictlyImmutable對象的值!<br />
        

        而如果getList()函數不直接返回mList引用,創建一個副本,或者使其不可被改變,則可以達到”嚴格意義上的“immutable。例如:

           public class NonStrictlyImmutable {
                private final List<Integer> mList = new ArrayList<>();

            public List<Integer> getList() {
                // 以下兩種方式都可以,各有優劣
                // return new ArrayList<>(mList);
                // return Collections.unmodifiableList(mList);
        
                return Collections.unmodifiableList(mList);
            }
        }</pre><br />
        

        上面兩種方式各有優劣:前者允許對新獲取到的副本進行修改操作而不會拋出異常,但會把底層數組數據創建多份;后者不會創建多份底層數組數據,但是如果對getList()返回的引用進行修改操作,將會拋出異常;見仁見智。

        • unmodifiable:unmodifiable不等于immutable,所以對于前面提到的建議做法,直接傳入unmodifiable是不對的,因為這樣只能阻止被調用方修改傳入數據后導致調用方出錯,并不能阻止調用方修改后導致被調用方出錯。unmodifiable并未拷貝底層數組數據,而是實現了另外一個List的實現類,該類的修改操作均拋出異常。
        • </ul> https://github.com/Piasy/notes/blob/master/misc/copy.md

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!