Java/Java

Java 깊은 복사(Deep Copy) 와 얕은 복사( Shallow Copy)

검은고양이개발자 2023. 2. 1. 19:12
반응형

 

깊은 복사와 얕은 복사의 의미


깊은 복사와 얕은 복사를 단순하고 명료하게 정리해 보면

얕은 복사(shallow copy)는 복사한 배열이 원래 배열의 '주소값'을 가져오고

깊은 복사(deep copy)는 복사한 배열이 원래 배열을 '그대로 가져온다 정도로 정리해 볼 수 있습니다.

 

얕은 복사는 복사하려는 배열의 주소값을 가져오며, 단순한 변수 선언을 통한 복사의 형태이고,

그래서 복사한 배열을 수정할 경우, 원래 배열도 같이 수정되게 됩니다.

(예를 들어 자물쇠의 열쇠를 복사하는 것과 같아, 복사한 열쇠를 통해 자물쇠를 열어 그 안의 내용을 바꾸면

기존의 열쇠를 통해 열어도 그 안의 내용물이 변화되는 것과 같습니다.)

 

 

반면에 깊은 복사는 새로운 배열에 원래 배열을 복사하는 겁니다.

따라서 복사한 배열을 수정하더라도, 원래 배열에 영향을 주지 않습니다.

(복사본을 아무리 바꿔도 원본에 영향 x) 

 

깊은 복사는 배열의 차원에 따라 이용할 수 있는 방법이 달라지기에 1차원, 2차원 배열로 나누어 알아보겠습니다.

 

 

얕은 복사(Shallow Copy)   1차원


 

 

public class Copy {
    public static void main(String[] args) {
        int[] CordJg = {1,2,3,4,5};
        int[] Cat = CordJg;

        System.out.println(Arrays.toString(Cat)); //출력  [1, 2, 3, 4, 5]

        Cat[4]= 100;

        System.out.println(Arrays.toString(Cat)); //출력 [1, 2, 3, 4, 100]
        System.out.println(Arrays.toString(CordJg)); //출력 [1, 2, 3, 4, 100]
    }
}

 

코드를 살펴보면 int [ ] Cat = CordJg ; 를 통해

단순 변수 선언을 했고 Cat의 출력값을 보면 CordJg와 같은 배열을 띄는 것을 볼 수 있습니다.

여기서 Cat [4]에 100을 넣어준 결과

Cat, CordJg 배열 각각이 모두 값이 변화된 걸 볼 수 있습니다.

 

우린 이런 복사를 얕은 복사라 부릅니다.

 

 

깊은 복사(Deep Copy)   1차원


 

public class Copy {
    public static void main(String[] args) {
        int[] CordJg = {1,2,3,4,5};
        int[] Cat = CordJg.clone();

        System.out.println(Arrays.toString(Cat)); //출력 [1, 2, 3, 4, 5]

        Cat[4]= 100;

        System.out.println(Arrays.toString(Cat)); //출력 [1, 2, 3, 4, 100]
        System.out.println(Arrays.toString(CordJg)); //출력 [1, 2, 3, 4, 5]
    }
}

 

코드를 살펴보면 위에 얕은 복사와 다른 점은 딱 하나

int [ ] Cat을 선언할 때 CordJg 뒤에. clone()을 붙여준 것입니다.

간단하게. clone()을 통해 깊은 복사를 해줄 수 있습니다.

 

출력 값을 봐보면 Cat 배열의 값을 변경해 줘도 CordJg 배열의 값은 기존 그대로인 것을 확인할 수 있습니다.

 

 

 

얕은 복사(Shallow Copy)   2차원


 

public class Copy {
    public static void main(String[] args) {
        int[][] CordJg = {{1,2,3},{4,5}};
        int[][] Cat = CordJg.clone();
        int[][] newCat = CordJg;

        System.out.println(Arrays.deepToString(Cat));  //출력 [[1, 2, 3], [4, 5]]
        System.out.println(Arrays.deepToString(newCat)); //출력 [[1, 2, 3], [4, 5]]

        Cat[0][0]= 100;

        System.out.println(Arrays.deepToString(Cat)); //출력 [[100, 2, 3], [4, 5]]
        System.out.println(Arrays.deepToString(CordJg)); //출력 [[100, 2, 3], [4, 5]]
    }
}

 

코드를 보면  1차원 배열에서는 깊은 복사가 됐던. clone()을 이용했음에도

단순 변수 선언을 한 것과 같이 얕은 복사가 된 것을 확인할 수 있습니다.

 

아쉽게도 1차원 배열과는 다르게. clone()을 이용한 간단한 깊은 복사는 2차원 배열에서는 불가능합니다.

 

# 2차원 배열을 읽기 위해서는 Arrays.deepToString()을 이용합니다.

 

 

 

깊은 복사(Deep Copy)   2차원


1.  2중 for문을 이용하는 방법

 

public class Copy {
    public static void main(String[] args) {
        Integer[][] CordJg = {{1,2},{4,5}};
        Integer[][] Cat = new Integer[CordJg.length][CordJg[0].length];

        for(int i=0; i< CordJg.length; i++){
            for(int j=0; j<CordJg[i].length; j++){
                Cat[i][j] = CordJg[i][j];
            }
        }

        System.out.println(Arrays.deepToString(Cat)); //출력 [[1, 2], [4, 5]]
        
        Cat[0][0]= 100;

        System.out.println(Arrays.deepToString(Cat)); //출력 [[100, 2], [4, 5]]
        System.out.println(Arrays.deepToString(CordJg)); //출력 [[1, 2], [4, 5]]
    } 
}

 

2중 for 문을 이용하면 깊은 복사를 할 수 있습니다.

 

배열의 크기는,

Integer [ ] [ ]  첫 번째 칸에는 CordJg의 요소 개수를 (CordJg.length)

두 번째 칸에는 CordJg의 0번째 인덱스에 있는 배열의 요소의 개수를 (CordJg [0]. length)

를 넣어줘서 크기를 정해주면 됩니다.

 

깊은 복사를 한 Cat의 값을 변경해 줘도 CordJg 2차원 배열의 값이 변하지 않는 것을 확인할 수 있습니다.

 

 

 

 

2. for 문 + System.arraycopy 복사

 

public class Copy {
    public static void main(String[] args) {
        Integer[][] CordJg = {{1,2},{4,5}};
       
        Integer[][] Dog = new Integer[CordJg.length][CordJg[0].length];

        for(int i=0; i< CordJg.length; i++){
            System.arraycopy(CordJg[i],0,Dog[i],0,Dog[i].length);
        }

        Dog[0][0]= 200;

        System.out.println(Arrays.deepToString(Dog)); //출력 [[200, 2], [4, 5]]
        System.out.println(Arrays.deepToString(CordJg));  //출력 [[1, 2], [4, 5]]
    }
}

 

2중 for문이 아닌  System.arraycopy + for 문을 통해서도 깊은 복사를 할 수 있습니다.

결괏값을 보면 깊은 복사가 이루어진 것을 확인할 수 있습니다.

 

반응형

'Java > Java' 카테고리의 다른 글

[Java] JDK 환경변수 설정 방법 및 이유  (0) 2023.07.27
Java_ Optional Class  (0) 2023.02.21
Java _ 래퍼 클래스(Wrapper Class)  (0) 2023.01.29
Java StringBuilder vs StringBuffer /Thread  (0) 2023.01.21
Java Thread  (0) 2023.01.21