Java 관련/Java

[Java] 얖은값 복사(Shallow copy), 깊은값 복사(Deep copy)

씨네 2021. 10. 19. 12:22
728x90


1. 얕은 값 복사(ShallowCopy) - 주소값 복사

package com.test01; 

import java.util.Arrays; 

public class ShallowCopy { 

  //얕은 값 복사(주소값 복사) 
  public static void main(String[] args) { 
    int[] original = {10, 20, 30, 40, 50}; 
    int[] copy = original; 

    System.out.println(Arrays.toString(original)); 
    System.out.println(Arrays.toString(copy)); 
    System.out.println(original); 
    System.out.println(copy); 

    copy[2] = 300; 
    
    System.out.println(Arrays.toString(original)); 
    System.out.println(Arrays.toString(copy)); 
  } 
}

위 코드의 실행 결과입니다. 한 줄씩 설명해드릴게요.

int[] original = {10, 20, 30, 40, 50}; 
int[] copy = original;

우선 original이라는 이름의 배열을 만들어서 값을 넣어주었습니다.

그러고 copy라는 이름의 배열을 만들어서 original을 통째로 대입했습니다.

System.out.println(Arrays.toString(original)); 
System.out.println(Arrays.toString(copy));

original과 copy의 값을 직접 보여주는 Arrays.toString을 통해 배열을 출력한 결과 두 배열 모두 같은 값이 나왔습니다.

System.out.println(original); 
System.out.println(copy);

두 개의 주소값을 출력해본 결과 주소값도 같습니다.

original과 copy는 완전히 같은 분신 같은 존재라는 의미죠.

copy[2] = 300;

copy의 2번 방에 300을 다시 대입했습니다.

( original에는 대입하지 않았습니다. )(방은 0번 방부터 시작입니다 )

System.out.println(Arrays.toString(original)); 
System.out.println(Arrays.toString(copy));

두 개의 값을 다시 출력해본 결과 original의 2번 방의 값도 변경되었습니다.

위의 방법처럼 직접 대입을 하면 주소값까지 정말 똑같은 복제되어 연결된 형태의 이름만 다른 배열이 복사됩니다.

2. 깊은 값 복사(DeepCopy) - 인덱스 값 복사

package com.test01; 

import java.util.Arrays; 

public class DeepCopy { 

//새로운 객체 생성해서, 값만 복사 
public static void main(String[] args) { 

  int[] original = {10, 20, 30, 40, 50}; 
  
  //1. 배열 인덱스의 값을 가져와서 복사 
  int[] copy01 = new int[original.length]; 
  
  for(int i = 0; i < original.length; i++) { 
  	copy01[i] = original[i]; 
  } 
  
  System.out.println(Arrays.toString(original)); 
  System.out.println(Arrays.toString(copy01)); 
  System.out.println(original); 
  System.out.println(copy01); 
  System.out.println(original == copy01);
  
  copy01[2] = 300;
  
  System.out.println(Arrays.toString(original));
  System.out.println(Arrays.toString(copy01));
  
  System.out.println("-------------------");

  //2. original에게 요청하여 복사 
  int[] copy02 = original.clone();
  
  System.out.println(Arrays.toString(original));
  System.out.println(Arrays.toString(copy02));
  
  copy02[2] = 3000;
  
  System.out.println(Arrays.toString(original));
  System.out.println(Arrays.toString(copy02));
  System.out.println(original);
  System.out.println(copy02);

  //3. System.arrayCopy 사용
  int[] systemArr = new int[10];
  Arrays.fill(systemArr, 100);
  System.out.println(Arrays.toString(systemArr));
  
  System.arraycopy(original, 0, systemArr, 1, 3); // 원본, 시작, 복사본, 시작, 갯수 
  System.out.println(Arrays.toString(systemArr));
  }
}

Shallow copy의 경우 객체 자체를 복사했다고 한다면 Deep copy는 새로운 객체를 만들어서 index 값만 복사했다고 이해하시면 될 것 같습니다.

int[] original = {10, 20, 30, 40, 50}; 

//1. 배열 인덱스의 값을 가져와서 복사 
int[] copy01 = new int[original.length]; 

for(int i = 0; i < original.length; i++) { 
	copy01[i] = original[i]; 
}

먼저 original 배열을 만들어 값을 넣어줬습니다.

이후 copy01 배열에 인덱스 값을 하나씩 가져와서 대입해 줍니다.

( 인덱스 값의 복사는 편의상 반복문 사용했습니다 )

System.out.println(Arrays.toString(original)); 
System.out.println(Arrays.toString(copy01));

이후 두 배열의 값을 출력해 봤을 때 당연히 같겠지요?

System.out.println(original); 
System.out.println(copy01);

주소값을 비교해봤더니 주소값이 다릅니다.

System.out.println(original == copy01);

original과 copy01이 같냐고 물어봤는데 false가 나옵니다. 주소값을 비교했을 때 다르니...

주소값 말고 인덱스 값을 비교해 주려면

System.out.println(original.equals(copy01)); 
System.out.println(Arrays.toString(original) == Arrays.toString(copy01));

이렇게 Arrays.toString을 이용하던가 equals를 이용해서 비교해야 합니다.

copy01[2] = 300; 

System.out.println(Arrays.toString(original)); 
System.out.println(Arrays.toString(copy01));

copy01의 2번 방에 300의 값을 대입하고 값을 출력해봤더니 original은 변화가 없고 copy01에만 대입되었습니다.

int[] copy02 = original.clone(); 

System.out.println(Arrays.toString(original)); 
System.out.println(Arrays.toString(copy02));

이번에는 clone()을 이용해 복사를 해보겠습니다. 각 배열 안에 들어있는 인덱스 값은 같습니다.

copy02[2] = 3000; 

System.out.println(Arrays.toString(original)); 
System.out.println(Arrays.toString(copy02));

copy02의 2번 방에 3000을 대입하고 인덱스 값을 출력해보니 original은 변화가 없고 복사본에만 값이 대입되었습니다.

System.out.println(original); 
System.out.println(copy02);

두 개의 주소값을 비교해보니 역시 주소값이 다르네요.

//3. System.arrayCopy 사용 
int[] systemArr = new int[10]; 
Arrays.fill(systemArr, 100); 
System.out.println(Arrays.toString(systemArr)); 

// 원본, 시작, 복사본, 시작, 갯수 
System.arraycopy(original, 0, systemArr, 1, 3); 
System.out.println(Arrays.toString(systemArr));

3번째 복사 방법은 한 번에 설명하겠습니다.

먼저 systemArr을 선언하고 정의합니다.

이후 syatemArr 배열의 각 요소에 100값을 할당합니다.

출력해보면 0번 방부터 9번 방까지 10개의 방에 100의 값이 들어갑니다.

System.arraycopy를 사용하여 복사를 합니다. (복사본에 원본을 복사합니다)

그러면 복사한 부분만 복사가 되어있습니다.

System.arraycopy(original, 0, systemArr, 1, 3);

이 부분만 자세히 알아볼게요.

System.arraycopy(원본, 어디서부터시작?, 복사본, 어디서부터시작, 몇칸이나?);

original의 0번 방부터 복사를 할 건데 systemArr의 1번 방부터 붙여 넣을 것이다.

복사는 3칸만 할 것이다. 라는 의미입니다.

728x90