일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 데이터베이스
- JPA
- Service Locator
- db
- Proxy Patter
- NotBlank
- @ControllerAdvice
- restTemplate
- java
- multi module
- Effetive Java
- @SpyBean
- Connection Pool
- 디자인 패턴
- Web
- Service Locator 패턴
- 이펙티브 자바
- Effective Java
- Firebase
- NotEmpty
- SQL 삽입 공격
- 플라이웨이트
- springboot
- @Valid
- Spring Boot
- @MockBean
- FCM
- Item04
- 트랜잭션
- deleteById
- Today
- Total
NoTimeForDawdling
얕은 복사(Shallow Copy) vs 깊은 복사(Deep Copy) 본문
개발을 하다 보면 객체를 복사할 때가 있을 겁니다. 객체의 복사는 얕은 복사와 깊은 복사 두 개념으로 나뉩니다. 단어만 보고 어떤 개념인 것 같은지 느낌이 오시나요??
어떤 느낌일 것 같은지 생각해 보셨다면 생각한 것과 일치하는지 한번 알아보겠습니다!
얕은 복사란?(Shallow copy)
- 얕은 복사란 객체의 참조값(주소값)을 복사하는 것을 의미합니다.
- 복사된 객체는 원본 객체와 같은 주소값을 참조합니다.
- 그렇기 때문에 복사된 객체의 값이 바뀌면 원본 객체의 값 또한 바뀌게 됩니다.
깊은 복사란?(Deep Copy)
- 깊은 복사란 객체의 실체 값을 복사하는 것을 의미합니다.
- 복사될 객체에 새 주소를 할당하여 원본 객체의 모든 값을 복사합니다.
- 원본 객체의 주소 값을 참조하지 않기 때문에 복사된 객체의 변화가 원본 객체에게 영향을 미치지 않습니다.
얕은 복사 코드 예제
import java.util.ArrayList;
public class ShallowCopy {
public static void main(String[] args) {
ArrayList<String> originObject = new ArrayList<>();
originObject.add("apple");
originObject.add("banana");
originObject.add("grape");
//얕은 복사 수행!
ArrayList<String> shallowCopyObject = originObject;
printObject(originObject, shallowCopyObject);
//복사된 객체에 strawberry 값 추가!!
System.out.println("복사된 객체에 값 strawberry 값 추가 후");
System.out.println("-------------------------------");
shallowCopyObject.add("strawberry");
printObject(originObject, shallowCopyObject);
// 동일성 검사
System.out.println("동일성 검사 결과");
System.out.println(originObject == shallowCopyObject);
}
private static void printObject(ArrayList<String> originObject, ArrayList<String> copyObject) {
System.out.println("원본 객체 값 출력!");
System.out.println(originObject.toString());
System.out.println();
System.out.println("얕은 복사된 객체 값 출력!");
System.out.println(copyObject.toString());
System.out.println();
}
}
결과는 위와 같습니다.
분명 shallowCopyObject에만 값을 추가하였는데 originOject에도 값이 추가된 것을 볼 수 있습니다.
동일성 검사 결과 또한 true를 반환하는 것으로 보아 주소 값이 일치한다는 것을 알 수 있습니다.
깊은 복사 코드 예제
import java.util.ArrayList;
public class DeepCopy {
public static void main(String[] args) {
ArrayList<String> originObject = new ArrayList<>();
originObject.add("apple");
originObject.add("banana");
originObject.add("grape");
//깊은 복사 수행!
ArrayList<String> deepCopyObject = new ArrayList<>(originObject);
printObject(originObject, deepCopyObject);
//복사된 객체에 strawberry 값 추가!!
System.out.println("복사된 객체에 값 strawberry 값 추가 후");
System.out.println("-------------------------------");
deepCopyObject.add("strawberry");
printObject(originObject, deepCopyObject);
// 동일성 검사
System.out.println("동일성 검사 결과");
System.out.println(originObject == deepCopyObject);
}
private static void printObject(ArrayList<String> originObject, ArrayList<String> copyObject) {
System.out.println("원본 객체 값 출력!");
System.out.println(originObject.toString());
System.out.println();
System.out.println("깊은 복사된 객체 값 출력!");
System.out.println(copyObject.toString());
System.out.println();
}
}
결과는 위와 같습니다.
deepCopyObject에 추가한 값이 originOject에는 영향을 미치지 않은 것을 볼 수 있습니다.
동일성 검사 결과 또한 false를 반환하는 것으로 보아 주소값이 일치하지 않는다는 것을 알 수 있습니다.
ArrayList의 Item으로 Object가 선언되어 있다면 어떻게 될까?
만약에 ArrayList의 Item으로 Object가 선언되어 있으면 어떻게 될까요? 깊은 복사가 잘 이뤄질까요??
한번 확인해 보겠습니다.
class Fruit{
private String name;
private String color;
public Fruit(String name, String color){
this.name = name;
this.color = color;
}
public String getName() {
return name;
}
public String getColor() {
return color;
}
@Override
public String toString() {
return "Fruit{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
'}';
}
}
import java.util.ArrayList;
public class ArrayListDeepCopy {
public static void main(String[] args) {
ArrayList<Fruit> originObject = new ArrayList<>();
originObject.add(new Fruit("apple", "red"));
originObject.add(new Fruit("banana", "yellow"));
originObject.add(new Fruit("grape", "purple"));
//깊은 복사 수행!
ArrayList<Fruit> deepCopyObject = new ArrayList<>(originObject);
printObject(originObject, deepCopyObject);
//복사된 객체에 strawberry 값 추가!!
System.out.println("복사된 객체에 값 strawberry 값 추가 후");
System.out.println("-------------------------------");
deepCopyObject.add(new Fruit("strawberry", "red"));
printObject(originObject, deepCopyObject);
// 동일성 검사
System.out.println("동일성 검사 결과");
System.out.println(originObject == deepCopyObject);
}
private static void printObject(ArrayList<Fruit> originObject, ArrayList<Fruit> copyObject) {
System.out.println("원본 객체 값 출력!");
System.out.println(originObject);
System.out.println();
System.out.println("깊은 복사된 객체 값 출력!");
System.out.println(copyObject.toString());
System.out.println();
}
}
Fruit이라는 클래스를 선언하고 ArraysList 안에 Fruit이라는 클래스를 저장시키도록 구현했습니다.
위의 결과만 봐서는 깊은 복사가 제대로 이뤄진 것 같습니다.
그렇다면 List에 선언한 Fruit 객체까지 깊은 복사가 이뤄졌을까요? 확인해보겠습니다!
import java.util.ArrayList;
public class ArrayListDeepCopy {
public static void main(String[] args) {
ArrayList<Fruit> originObject = new ArrayList<>();
originObject.add(new Fruit("apple", "red"));
originObject.add(new Fruit("banana", "yellow"));
originObject.add(new Fruit("grape", "purple"));
//깊은 복사 수행!
ArrayList<Fruit> deepCopyObject = new ArrayList<>(originObject);
//복사된 객체의 Fruit 객체 값 변경!!
System.out.println("복사된 객체의 Fruit 객체 값 변경 후");
System.out.println("-------------------------------");
final Fruit fruit = deepCopyObject.get(0);
fruit.changeName("cherry");
printObject(originObject, deepCopyObject);
}
private static void printObject(ArrayList<Fruit> originObject, ArrayList<Fruit> copyObject) {
System.out.println("원본 객체 값 출력!");
System.out.println(originObject);
System.out.println();
System.out.println("깊은 복사된 객체 값 출력!");
System.out.println(copyObject.toString());
System.out.println();
}
}
복사된 객체의 Fruit 값을 apple -> cherry로 변경했습니다.
결과를 보시면 원본 객체의 apple 값까지 cherry로 변경된 것을 확인할 수 있습니다.
ArrayList 자체의 주소 값은 다르지만 Item으로 선언한 객체까지는 깊은 복사를 수행하지 못한 것 같습니다.
해결 방법으로는 해당 객체(Fruit)에 대한 깊은 복사를 수행해주면 됩니다.
...
for(Fruit fruit : origin){
copy.add(new Fruit(fruit));
}
'Java' 카테고리의 다른 글
기본형(Primitive Type)과 참조형(Reference Type) (0) | 2021.03.02 |
---|---|
일급 컬렉션(First Class Collection) (0) | 2021.03.01 |
접근 제어자(Access Modifier) (0) | 2021.02.24 |
Enum 클래스 파헤치기 (0) | 2021.02.23 |
[Java] 불변 리스트(Immutable ArrayList) (0) | 2021.02.15 |