Cloneable 인터페이스는 인스턴스가 복제 가능하도록 하기 위해서 구현해야 하는 인터페이스이다. 가장 간단한 사용법은 다음과 같다.
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 | public class Car implements Cloneable { private String brand; private int price; public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } } | cs |
일단 저렇게 복제가 가능하도록 하긴 했습니다만, 여기서 한가지 짚고 넘어가야 하는 개념이 생긴듯 합니다. 복제라는 개념이 정확히 무슨 의미일까요?
복제는 deep copy와 shallow copy로 다시 나뉘게 됩니다. 결론부터 말하자면 deep copy는 한 인스턴스의 내용을 복제하여 새로운 메모리 공간에다가 생성한다는 의미라고 보면 되겠고, shallow copy는 복제의 대상을 참조하는 또다른 인스턴스를 만드는 행위라고 할 수 있겠습니다. 위의 코드를 참조하여 아래와 같이 인스턴스 4개를 생성하고, 이중 2개 인스턴스는 각각 다른 인스턴스를 deep copy한것과 shallow copy해보기로 하였습니다.
| Car car1 = new Car(); car1.setBrand("Hyundai Motors"); Car car2 = new Car(); car2.setBrand("Mercedes Benz"); // shallow copy Car car3 = car1; Car car4 = new Car4(); try { // example of deep copy car4 = car2.clone(); } catch(CloneNotSupportedException e) { System.out.println(e.getMessage()); } | cs |
만들어진 인스턴스의 해시코드를 확인해 보고자 다음과 같이 각 인스턴스의 해시코드를 출력해 보기로 하였습니다.
| System.out.println(car1.hashCode()); System.out.println(car2.hashCode()); System.out.println(car3.hashCode()); System.out.println(car4.hashCode()); | cs |
그리고 그 결과는 다음과 같습니다.
| 1829164700 2018699554 1829164700 1311053135 | cs |
즉, shallow copy를 한 car3 인스턴스는 car1과 같은 해시코드를 공유하는 반면 deep copy를 한 car4 인스턴스는 새로운 해시코드를 갖는다는 것을 확인할 수 있습니다.