코딩테스트를 보면서 Queue를 여러 메소드에서 사용하다가 요소가 여러개 삭제되는 경우가 있었다. 파라미터로 보낸 Queue에서 요소를 삭제하면 원본 Queue에도 영향을 미치는 문제였으며, String 같은 변수를 넘길 때는 파라미터 값을 변경해도 원본에는 영향을 미치지 않았다. 이 개념을 정리하기 위해 글을 작성한다. 한 가지 간단한 테스트를 해보자.
위 코드는 다음과 같은 작업을 수행한다.
String은 타 메소드에서 변경을 해도 그대로 출력되는데, String[]은 타 메소드에서 변경된 값이 출력되는 것을 확인할 수 있다. 왜 이런걸까? 를 알기 위해선 우선 얕은 복사와 깊은 복사에 대한 개념을 알아야 한다. 얕은 복사; Shallow Copy
깊은 복사; Deep Copy
기본 자료형 변수가 파라미터로 던져지면 값을 던지지만, Array, List 등의 변수가 파라미터로 던져지면 주소를 던진다. 전자는 깊은 복사, 후자는 얕은 복사로 이해하면 된다. (Call by Value, Call by Reference을 구글링하면 더 많은 정보를 볼 수 있다.) 그렇다면 Array나 List 등을 깊은 복사를 하고 싶으면 다음과 같은 방법을 선택하면 된다.
+ 참고로 List에서 제공하는 Collections.copy()나 addAll() 같은 메소드들은 Shallow Copy다 Clone
기본적으로 clone()을 그냥 이용하면 shallow copy가 진행된다. + 예외로 Array의 경우에는 clone() 메소드를 바로 사용해도 deep copy가 된다. + Arrays.copyOf(), copyOfRange() 메소드도 deep copy. 하지만 clone()를 오버라이딩하면 deep copy를 할 수 있다. 이를 위해서는 3가지 조건이 필요하다.
Cloneable 인터페이스란? ▼ 더보기 Cloneable interface
CloneNotSupportedException이란? ▼ 더보기 CloneNotSupportedException
예제clone()을 오버라이딩 해볼 간단한 TestClass를 작성해보았다.
(생략된 부분에는 생성자와 getter, settter 메소드 정도만 선언해두었다.) 이제 clone() 메소드를 실행시켜보자.
확인 결과 = 연산자로 복사한 test2는 shallow copy가, clone() 메소드로 복사한 test3는 deep copy가 이루어진 것을 확인할 수 있다. 하지만 clone() 메소드를 오버라이딩 할 때는 유의할 점이 있어 오버라이딩을 권장하지 않는 사람들이 많다. 이 부분에 대해서는 나중에 포스팅 하겠다. 참조 1. https://jyosssss.tistory.com/78 2. https://developer-youngjun.tistory.com/20 3. https://atoz-develop.tistory.com/entry/JAVA-List-%EA%B0%9D%EC%B2%B4-%EB%B3%B5%EC%82%AC-%EB%B0%A9%EB%B2%95%EA%B3%BC-Collections-copy 4. https://docs.oracle.com/javase/7/docs/api/java/lang/Cloneable.html 5. https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#clone() |