개발 & 데이터베이스/JAVA

[JAVA] 얕은 복사와 깊은 복사에 대해서 알아보기

K.두부 2022. 12. 26. 23:09
반응형

자바에는 얕은 복사 (Shallow Copy) 깊은 복사 (Deep Copy) 가 존재한다.

 

얕은 복사는 복사하려는 배열의 '주소값'을 복사함

깊은 복사는 '실제값'을 새로운 메모리 공간에 복사함

 

1차원 배열

- 얕은 복사

  • 복사하려는 배열의 주소값을 가져옴
  • 두 개의 배열 중 하나라도 값을 수정한다면 둘 다 수정됨
int[] A = {1, 2, 3};
int[] B = A;
        
B[0] = 5;
A[2] = 10;
        
System.out.println(A[0]); // 5
System.out.println(B[2]); // 10

B[0]을 수정했지만 A[0]의 값도 변경되고, A[2]를 수정했지만 B[2]의 값도 같이 변하는 것을 볼 수 있다.

 

- 깊은 복사

  • 복사하려는 배열의 주소값이 아닌 실제값을 가져와서 새로운 메모리 공간에 복사함
  • 두 개의 배열이 서로 영향을 받지않음
int[] A = {1, 2, 3};
int[] B = A.clone();
        
B[0] = 5;
A[2] = 10;
        
System.out.println(A[0]); // 1
System.out.println(B[2]); // 3

B[0]을 수정했지만 A[0]의 값에는 영향이 없는 것을 확인할 수 있다. B 배열 또한 A 배열에 영향이 없다.

 

2차원 배열

- 얕은 복사

int[][] A = {{1, 2, 3},
             {4, 5, 6},
             {7, 8, 9}};
int[][] B = A.clone();
        
B[0][0] = 5;
A[2][2] = 10;
        
System.out.println(A[0][0]); // 5
System.out.println(B[2][2]); // 10

1차원 배열에서의 A.clone() 은 깊은 복사가 되었지만 2차원 배열에서 사용하게 되면 얕은 복사가 된다. 즉, B 배열의 값을 변경하게 되면 A 배열의 값도 같이 변한다.

 

- 깊은 복사

  • 2중 반복문
  • 반복문 + System.arraycopy(복사하려는 배열, 복사하려는 배열의 시작 위치, 새 배열, 새로운 배열의 시작 위치, 길이)
int[][] A = {{1, 2, 3},
             {4, 5, 6},
             {7, 8, 9}};
int[][] B = new int[3][3];
        
for (int i=0; i<3; i++) {
    for (int j=0; j<3; j++) {
        B[i][j] = A[i][j];
    }
}
        
B[0][0] = 5;
A[2][2] = 10;
        
System.out.println(A[0][0]); // 1
System.out.println(B[2][2]); // 9
        
int[][] C = new int[3][3];
        
for (int i=0; i<3; i++) {
    System.arraycopy(A[i], 0, C[i], 0, 3);
}
        
A[1][1] = 15;
C[1][2] = 10;
        
System.out.println(C[1][1]); // 5
System.out.println(A[1][2]); // 6

2차원 배열에서는 두 가지 방법으로 깊은 복사를 할 수 있다. 

 

객체 배열

- 얕은 복사

public static class Pos {
    int x, y;
        
    public Pos (int x, int y) {
        this.x = x;
        this.y = y;
    }
}
    
public static void main(String[] args) throws IOException {
    Pos[] A =  new Pos[3];
        
    for (int i=0; i<3; i++) {
        A[i] = new Pos(i, i);
    }
        
    Pos[] B = A;
    B[0].x = 5;
    B[0].y = 5;
    
    Pos[] C = new Pos[3];
    for (int i=0; i<3; i++) {
        C[i] = A[i];
    }
        
    C[1].x = 10;
    C[1].y = 10;
    
    Pos[] D = new Pos[3];
    System.arraycopy(A, 0, D, 0, A.length);
        
    D[2].x = 20;
    D[2].y = 20;
        
    System.out.println(A[0].x + " :: " + A[0].y); // 5 :: 5
    System.out.println(A[1].x + " :: " + A[1].y); // 10 :: 10
    System.out.println(A[2].x + " :: " + A[2].y); // 20 :: 20
}

 

- 깊은 복사

public static class Pos {
    int x, y;
        
    public Pos (int x, int y) {
        this.x = x;
        this.y = y;
    }
}
    
public static void main(String[] args) throws IOException {
    Pos[] A =  new Pos[3];
        
    for (int i=0; i<3; i++) {
        A[i] = new Pos(i, i);
    }
        
    Pos[] B = A.clone();
    B[0] = new Pos(5,5);
        
    Pos[] C = new Pos[3];
    for (int i=0; i<3; i++) {
        C[i] = new Pos(A[i].x, A[i].y);
    }
        
    C[1].x = 10;
    C[1].y = 10;
        
    Pos[] D = new Pos[3];
    System.arraycopy(A, 0, D, 0, A.length);
        
    D[2] = new Pos(20, 20);
        
    System.out.println(A[0].x + " :: " + A[0].y); // 0 :: 0
    System.out.println(A[1].x + " :: " + A[1].y); // 1 :: 1
    System.out.println(A[2].x + " :: " + A[2].y); // 2 :: 2
}

객체 배열에서의 얕은 복사와 깊은 복사의 차이점은 배열의 값을 변경하거나 선언할 때 new 생성자의 유무이다. 얕은 복사에서는 new 생성자를 사용하지 않았고, 깊은 복사에서는 복사할 배열을 선언할 때, 값을 변경할 때 new 생성자를 사용했다. 

반응형