728x90

문제점 )
객체를 요소로 가진 A 배열이 있다. 새로운 B 배열을 만들고 A 배열의 요소들을 복사해서 저장하고 싶다. A 배열의 객체 요소를 변경해도 B 배열 내부의 요소들은 영향을 받지 않아야 한다. 어떻게 해야 할까?
해결책 )
깊은 복사를 배열 자체만 하면 안 된다. 배열 내부에 저장된 요소 하나하나 깊은 복사 해서 저장해야 한다.
배열을 복사하는 방법은 크게 2 가지다.
얕은 복사 (Shallow Copy)
얕은 복사는 해당 배열의 '주소값'을 복사하는 것이다.
따라서 원본 배열의 주소값을 복사했기 때문에 원본 배열의 요소를 변경하면
복사된 배열도 동일하게 수정된다.
int[] original = {1, 2, 3, 4, 5}; int[] copyArray = original; // 얕은 복사 original[0] = 9; // 원본 요소 수정 System.out.println(Arrays.toString(original)); // [9, 2, 3, 4, 5] System.out.println(Arrays.toString(copyArray)); // [9, 2, 3, 4, 5]
깊은 복사 (Deep Copy)
깊은 복사는 해당 배열의 '값'을 복사하는 것이다.
주소값이 아니라 값만 복사하기 때문에 아예 새로운 배열로 만들어진다.
일반적으로 '복사'라고 하면 깊은 복사를 지칭한다.
int[] original = {1, 2, 3, 4, 5}; int[] copyArray = new int[5]; for (int i = 0; i < original.length; i++) { copyArray[i] = original[i]; // 깊은 복사 } original[0] = 9; // 원본 요소 수정 System.out.println(Arrays.toString(original)); // [9, 2, 3, 4, 5] System.out.println(Arrays.toString(copyArray)); // [0, 2, 3, 4, 5]
for문을 사용하지 않고도 '깊은 복사'를 할 수 있는 메서드가 존재한다.
- Object.clone ()int[] original = {1, 2, 3, 4, 5}; int[] copyArray = original.clone(); // 깊은 복사 original[0] = 9; // 원본 요소 수정 System.out.println(Arrays.toString(original)); // [9, 2, 3, 4, 5] System.out.println(Arrays.toString(copyArray)); // [0, 2, 3, 4, 5]
- Arrays.copyOf()int[] original = {1, 2, 3, 4, 5}; int[] copyArray = Arrays.copyOf(original, original.length); // 깊은 복사 original[0] = 9; // 원본 요소 수정 System.out.println(Arrays.toString(original)); // [9, 2, 3, 4, 5] System.out.println(Arrays.toString(copyArray)); // [0, 2, 3, 4, 5]
- Arrays.copyOfRange()int[] original = {1, 2, 3, 4, 5}; int[] copyArray = Arrays.copyOfRange(original, 0, original.length); // 깊은 복사 original[0] = 9; // 원본 요소 수정 System.out.println(Arrays.toString(original)); // [9, 2, 3, 4, 5] System.out.println(Arrays.toString(copyArray)); // [0, 2, 3, 4, 5]
- System.arraycopy()int[] original = {1, 2, 3, 4, 5}; int[] copyArray = new int[5]; System.arraycopy(original, 0, copyArray, 0, original.length); // 깊은 복사 original[0] = 9; // 원본 요소 수정 System.out.println(Arrays.toString(original)); // [9, 2, 3, 4, 5] System.out.println(Arrays.toString(copyArray)); // [0, 2, 3, 4, 5]
배열 내부의 요소가 원시형 타입이 아니라 참조형 타입, 즉 객체라면 단순히 위 메서드를 사용해선 안된다.
객체가 담긴 배열만 '깊은 복사'하더라도, 각각의 배열의 인덱스에 저장된 객체의 주소는 그대로 얕은 복사가 돼서 객체의 내용을 바꾸면 영향을 준다. 아래 코드를 보면 두 배열 내부의 객체 주소가 동일하다.
public class test {
public static void main(String[] args) {
A[] a = {new A(), new A(), new A()};
A[] b = a.clone(); // 깊은 복사
System.out.println(Arrays.toString(a));
System.out.println(Arrays.toString(b));
// [problem2.A@4eec7777, problem2.A@3b07d329, problem2.A@41629346]
// [problem2.A@4eec7777, problem2.A@3b07d329, problem2.A@41629346]
}
}
class A {
}
public class test {
public static void main(String[] args) {
A[] a = {new A(), new A(), new A()};
A[] b = Arrays.copyOf(a, 3); // 깊은 복사
System.out.println(Arrays.toString(a));
System.out.println(Arrays.toString(b));
// [problem2.A@4eec7777, problem2.A@3b07d329, problem2.A@41629346]
// [problem2.A@4eec7777, problem2.A@3b07d329, problem2.A@41629346]
}
}
class A {
}
따라서 배열 내부의 객체까지 모두 '깊은 복사'를 적용하고 싶다면 for 문을 이용해 배열 요소 하나씩 깊은 복사를 적용해야 한다. 아래 코드를 보면 배열의 각 요소가 가리키는 주소값이 상이하다. 비로소 진정한 깊은 복사가 이뤄졌다.
public class test {
public static void main(String[] args) {
A[] a = {new A(), new A(), new A()};
A[] b = new A[3];
for (int i = 0; i < a.length; i++) {
b[i] = a[i].clone(); // 요소 하나하나 깊은 복사
}
System.out.println(Arrays.toString(a));
System.out.println(Arrays.toString(b));
// [problem2.A@4eec7777, problem2.A@3b07d329, problem2.A@41629346]
// [problem2.A@404b9385, problem2.A@6d311334, problem2.A@682a0b20]
}
}
class A implements Cloneable {
public A clone() {
try {
return (A) super.clone();
} catch (CloneNotSupportedException e) {}
return null;
}
}'Java' 카테고리의 다른 글
| [Java] Optional 사용법 (0) | 2023.03.22 |
|---|---|
| [Java] Map 인터페이스에서 값(value)을 기준으로 정렬하기 (0) | 2022.09.14 |
| [Java] Math.random( ) 원하는 범위 설정하기 (0) | 2022.09.14 |
| [Java] String ← → 기본형 값 (feat. 형변환) (0) | 2022.09.09 |
| [Java] String 클래스의 replace() & replaceAll() 메서드 (0) | 2022.09.08 |