freeParksey
밥세공기
freeParksey
전체 방문자
오늘
어제
  • 분류 전체보기 (150)
    • JAVA (32)
      • 자바스터디 (21)
      • Java in action (6)
      • OOP (1)
      • test (2)
    • 알고리즘 문제 (51)
      • 백준 (49)
    • C (Atmega128) (7)
    • 인공지능 (11)
    • 운영체제 (8)
    • 디자인패턴 (5)
    • 잡다한것 (2)
    • 사용기 (3)
      • 도커 (3)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 3주차
  • Thread 동작
  • 집합과 맵
  • 그리드
  • 스트림
  • Collection
  • Python
  • 후기
  • 백트래킹
  • 자바스터디
  • dto 변환 위치
  • 우아한테크코스
  • 동작 파라미터화
  • 백준
  • Iterator
  • 동적계획법
  • generic
  • 우테코
  • 분류
  • 자바
  • 백트랙킹
  • java
  • 운영체제
  • Thread #JVM #자바스터디 #
  • dto 변환
  • 상속
  • 알고리즘
  • 딥러닝
  • 프리코스
  • 재귀기초

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
freeParksey

밥세공기

[Java] 깊은 복사 vs 얕은 복사
카테고리 없음

[Java] 깊은 복사 vs 얕은 복사

2022. 12. 1. 23:21

복사


코드를 작성하다 보면, 똑같은 값을 가지게 하고싶을 때가 있습니다.

따라서 아래와 같이 사용합니다

Integer a = 3;
Integer b = a;
a = 5;

 

모든 값이 이렇게 잘 복사되면 좋겠지만 배열이나 객체의 경우 다른 결과가 나옵니다.

 

배열의 복사


List<Integer> origin = new ArrayList<>(List.of(1,2,3));
List<Integer> copy = origin;

origin.set(0,10);
copy.add(0);

배열은 값을 복사하여 가져와도 두 값 전부 변경되는 것을 볼 수 있습니다.

 

Copy origin = new Copy(5);
Copy copy = origin;
origin.a = 10;

/**
 * 임의 클래스
 */
class Copy {
    int a;
    Copy(int a) {
        this.a = a;
    }
}

또한 클래스를 통한 객체에서도 위와 같은 결과가 나옵니다.

어떻게 된 것인가?

 

깊은 복사 vs 얕은 복사


객체를 복사하게 되었을 때
얕은 복사 : 원본과 복제된 값이 서로 같은 객체를 공유하고 있을 때, 원본과 복사본은 서로의 값에 영향을 준다.
깊은 복사 : 서로 다른 객체를 가지고 있지만, 같은 값을 가지고 있다. 원본과 복사본이 서로 영향을 주지 않는다.

 

값의 얕은 복사

자바에서는 모든 값을 넣어줄때 자신이 가지고 있는 값을 전달해 줍니다.

여기서 리스트로 생성하게 되면 힙에는 참조변수들(copy, origin)이 생성되며 new ArrayList<>()를 통해 스택 메머리에 할당을 받게 됩니다. 따라서 메모리에 올라오면서 주소를 가지게 되는데  위에서는 이 주소 값을 그대로 복사하여 전달해 줬기 때문에 위 결과와 같이 0번째 인덱스를 10으로 바꾸거나 0을 추가하여도 똑같았던 것입니다.

 

이러한 문제를 해결하기 위해 이러한 object들의 경우 clone을 제공합니다.

 

 

진행 전 print함수

출력하는 부분은 중요하지 않기 때문에 함수로 따로 빼서 설정했습니다

public static void print(Object object1, Object object2) {
    System.out.println(object1);
    System.out.println(object2);
}

 

Clone


ArrayList<Integer> list = new ArrayList<>(List.of(1,2,3));
ArrayList<Integer> list2 = (ArrayList<Integer>) list.clone();
print(list, list2);
list.set(0,3);
print(list,list2);

 

clone을 사용하게 되면 내부에 있는 값을 복사하여 넣기 때문에 위와 같이 변경된 값을 서로 구분할 수 있게 됩니다.

예를 들면,

이렇게 되는 거죠

 

List.copyOf()


List에도 똑같이 복사를 하는 메서드를 내장하고 있는데 List.copyOf() 메서드 입니다.

 

List<Integer> list = new ArrayList<>(List.of(1,2,3));
List<Integer> list2 = List.copyOf(list);
print(list,list2);

list.set(0,3);
print(list,list2);

clone과 동일한 동작을 하는 것을 볼 수 있습니다.

 

하지만, clone과 List.copyOf()에서도 단점이 있는데 객체 내부에 참조 변수가 존재하게 되면 여기서도 얕은 복사와 같은 일이 발생합니다.

 

왜 그럴까요?

 

두 메서드는 객체에 저장된 값을 그대로 복제하는 것이지 객체가 참조되는 값까지 복제하지는 않습니다.

따라서 참조 값을 포함하는 변수에서 깊은 복사를 위해서는 직접 모든 데이터를 넣어줘야 합니다.

 

public static List<Integer> deepCopy(List<Integer> numbers) {
    List<Integer> numbersCopy = new ArrayList<>();
    for (Integer number : numbers) {
        numbersCopy.add(number);
    }
    return numbersCopy;
}

 

    freeParksey
    freeParksey
    Github: https://github.com/parksey

    티스토리툴바