Java/[도서] 자바의 정석

배열의 얕은 복사, 깊은 복사

Lea Hwang 2022. 4. 27. 02:16

자바에서 객체를 복사할 때는 얕은 복사, 깊은 복사가 있습니다.

얕은 복사의 경우 객체의 주소 값을 복사하는 것이고 깊은 복사는 실제값을 복사해서 이 값을 새로운 메모리 공간에 복사하는 것입니다.

 

얕은 복사의 경우 여러 객체가 같은 주소를 참조하고 있기에 하나의 값이 변경되면 다른 대상의 값 또한 변경되는 문제가 발생하지만 깊은 복사는 이러한 문제가 발생하지 않습니다.

 

 

 

1차원 배열의 얕은 복사(Shallow Copy)

public class Copy {

	public static void main(String[] args) {
		int[] a = {1,2,3,4,5};
		int[] b = a;
		System.out.println(Arrays.toString(a)); // [1, 2, 3, 4, 5]

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


		// 원본 배열 값 변경
		a[1] = 22;
		System.out.println(Arrays.toString(a)); // [1, 22, 3, 4, 5]

		System.out.println(Arrays.toString(b)); // [1, 22, 3, 4, 5]


		// 복사한 배열 값 변경
		b[3] = 55;
		System.out.println(Arrays.toString(a)); // [1, 22, 3, 55, 5]

		System.out.println(Arrays.toString(b)); // [1, 22, 3, 55, 5]

	}

}

= 연산자는 주소를 이어준다는 의미로 a의 배열을 b배열로 = 연산자를 활용하여 대입하면 얕은 복사가 됩니다.

 

 

 

1차원 배열의 깊은 복사(Deep copy)

public class Copy {

	public static void main(String[] args) {
		int[] a = {1,2,3,4,5};
		int[] b = new int[a.length]; 
		for (int i = 0; i < a.length; i++) {
		    b[i] = a[i];
		}
		System.out.println(Arrays.toString(a)); // [1, 2, 3, 4, 5]

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


		// 원본 배열 값 변경
		a[1] = 123;
		System.out.println(Arrays.toString(a)); // [1, 123, 3, 4, 5]

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


		// 복사한 배열 값 변경
		b[3] = 789;
		System.out.println(Arrays.toString(a)); // [1, 123, 3, 4, 5]

		System.out.println(Arrays.toString(b)); // [1, 2, 3, 789, 5]


	}

}

복사한 배열을 수정하더라도 원본 배열이 변경되지 않습니다.

위와 같이 for문을 돌려가며 일일이 값을 옮겨도 되지만 자바에서 배열을 복사할 수 있는 여러 가지 메서드를 제공하고 있습니다.

 

 

배열 복사하는 여러 가지 메서드

Object.clone()

public class Copy {

	public static void main(String[] args) {
		int[] a = {1,2,3,4,5};
		int[] b = a.clone();
		
		System.out.println(Arrays.toString(b)); // [1, 2, 3, 4, 5]
	}

}

자바에서 모든 클래스의 부모 클래스는 Object 클래스이고 Object 클래스에는 clone() 메서드가 있습니다.

clone() 메소드를 이용해 새로운 배열을 생성하고 b변수에는 a변수와는 다른 참조값을 가지게 됩니다.

 

Arrays.copyOf() / Arrays.copyOfRange()

public class Copy {

	public static void main(String[] args) {
		int[] a = {1,2,3,4,5,6,7,8,9,10};

		// a 배열 전체 복사
		int[] b = Arrays.copyOf(a, a.length);
		int[] c = Arrays.copyOfRange(a, 0, a.length);
		
		System.out.println(Arrays.toString(b)); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
		System.out.println(Arrays.toString(c)); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

		// a 배열 처음부터 5개 복사 
		int[] b1 = Arrays.copyOf(a, 5);
		
		System.out.println(Arrays.toString(b1)); // [1, 2, 3, 4, 5]

		// a 배열 인덱스2부터 인덱스4'전'까지
		int[] c1 = Arrays.copyOfRange(a, 2, 4);
		
		System.out.println(Arrays.toString(c1)); // [3, 4]
	}

}

Arrays 클래스의 copyOf(), copyOfRange() 메소드를 사용하면 배열의 전체 또는 부분을 복사할 수 있습니다.

    차이점은,

    Arrays.copyOf() : 시작점 ~ 원하는 length까지 복사합니다.

    Arrays.copyOfRange() : 시작점의 위치 또한 지정할 수 있습니다.

 

System.arraycopy()

public class Copy {

	public static void main(String[] args) {
		int[] a = {1,2,3,4,5,6,7,8,9,10};

		// a 배열 전체 복사
		int[] b = new int[a.length];
		System.arraycopy(a, 0, b, 0, a.length);
		
		System.out.println(Arrays.toString(b)); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

		// a 배열 일부분 요소값 복사 (a배열 인덱스4부터 5개)
		int[] c = new int[5];
		System.arraycopy(a, 4, c, 0, 5);
		
		System.out.println(Arrays.toString(c)); // [5, 6, 7, 8, 9]
		
		// a 배열 일부분 요소값 복사 (a배열 인덱스2부터 3개)
		int[] d = new int[3];
		System.arraycopy(a, 2, d, 0, 3);
		
		System.out.println(Arrays.toString(d)); // [3, 4, 5]
	}

}

배열 전체 또는 일부분의 데이터를 복사할 수 있습니다.

 

 

 

2차원 배열의 깊은 복사

2차원 배열의 경우 앞서 살펴본 메서드로는 깊은 복사가 되지 않습니다. 이 경우 2중 for문을 돌리면서 일일이 복사해주거나 1중 for문 + 메서드들을 이용할 수 있습니다.

 

2중 for문

public class Copy {

	public static void main(String[] args) {
		int a[][] = { {1,2,3},{4,5,6},{7,8,9} };
		int b[][] = new int[a.length][a[0].length];

		for (int i = 0; i < a.length; i++) {
			for (int j = 0; j < a[i].length; j++){
				b[i][j] = a[i][j];
			}
		}
		
		System.out.println(Arrays.deepToString(b)); // [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
	}

}

 

Object.clone()

public class Copy {

	public static void main(String[] args) {
		int a[][] = {{1,2,3},{4,5,6},{7,8,9}};
		int b[][] = new int[a.length][a[0].length];

		for (int i = 0; i < a.length; i++) {
			b[i] = a[i].clone();
		}
		
		System.out.println(Arrays.deepToString(b)); // [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
	}

}

 

System.arraycopy()

public class Copy {

	public static void main(String[] args) {
		int a[][] = {{1,2,3},{4,5,6},{7,8,9}};
		int b[][] = new int[a.length][a[0].length];

		for(int i=0; i < b.length; i++){
			System.arraycopy(a[i], 0, b[i], 0, a[0].length);
		}
		
		System.out.println(Arrays.deepToString(b)); // [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
	}

}

 

 

 

 

 

 

출처 : 

https://seoyoung2.github.io/java/2021/01/21/java-copy.html

https://coding-factory.tistory.com/548