← go back

Clone Arraylist

핵심 → 배열의 요소가 참조형일 경우에는 각 원소에 대해 전부 clone을 해준다
배열을 복사하려면 어떻게 해야될까. shallow copy 문제와 더불어 배열을 복사하기 위한 방법을 살펴본다.


다음과 같은 Fruit 클래스가 있다.

public class Fruit {
    private String name;
    private int price;
    public Fruit(String name, int price) {
        this.name = name;
        this.price = price;
    }
		@Override
		    public String toString() {
		        return "{ " + this.name + ": " + this.price + " }";
		    }
}
ArrayList<Fruit> fruits = new ArrayList<>();
fruits.add(new Fruit("Apple", 3500));
fruits.add(new Fruit("Orange", 7500));

// fruit 배열 출력해보기
System.out.println(fruits); 
/**** 출력결과 ****

[{ Apple: 3500 }, { Orange: 7500 }]

*****************/

// fruit 배열을 clone 해본다 -> shallow copy일까?
ArrayList<Fruit> copyOfFruits = (ArrayList<Fruit>)fruits.clone();
System.out.println(System.identityHashCode(fruits));
System.out.println(System.identityHashCode(copyOfFruits));
/**** 출력결과 *****

114132791
586617651

--> 다른 주소값을 가진다, 메모리 안 배열의 시작 위치는 다름을 의미한다
*****************/

// 각 원소의 주소값을 출력해보자
for(Fruit e: fruits) {
    System.out.println(System.identityHashCode(e));
}

for(Fruit e: copyOfFruits) {
    System.out.println(System.identityHashCode(e));
}

/**** 출력결과 *****

328638398
1789550256
328638398
1789550256

--> 각 원소가 같은 주소값을 가진다
--> 배열의 원소가 같은 객체를 참조하고 있으며 이는 shallow copy임을 의미한다
*****************/

fruits, copyOfFruits 은 결국 같은 원소를 가진 것이나 다름없다. 각 원소가 같은 주소값을 가지기 때문이다. fruitsadd 메소드로 원소를 추가했을 때는 fruits에만 원소가 추가되겠지만, fruits의 원소를 setter메소드로 데이터 변경을 했을 때에는 fruits, copyOfFruits 모두 동일하게 변경될 것이다. 하지만 배열을 복사한다는 것은 원본 데이터를 그대로 보존하고 복사한 데이터를 가지고 변형할 것임을 의미할 것이다. 말그대로 deep copy가 필요한데, 그렇다면 각 원소에 대해 모두 clone을 통해 복사해주면 된다. 그러기 위해선 Fruit 클래스를 아래와 같이 수정해준다.


// Cloneable 인터페이스 구현 추가
public class Fruit implements Cloneable {
    private String name;
    private int price;
    public Fruit(String name, int price) {
        this.name = name;
        this.price = price;
    }
    @Override
    public String toString() {
        return "{ " + this.name + ": " + this.price + " }";
    }

    public void setPrice(int price) {
        this.price = price;
    }

    // clone 메소드 재정의
    @Override
    protected Fruit clone() throws CloneNotSupportedException {
        return (Fruit) super.clone();
    }
}

copyOfFruits 리스트에 각 원소를 clone 하여 add 해보자

ArrayList<Fruit> fruits = new ArrayList<>();
fruits.add(new Fruit("Apple", 3500));
fruits.add(new Fruit("Orange", 7500));

ArrayList<Fruit> copyOfFruits = new ArrayList<>();
System.out.println(System.identityHashCode(fruits));
System.out.println(System.identityHashCode(copyOfFruits));

for(Fruit e: fruits) {
    System.out.println(System.identityHashCode(e));
    copyOfFruits.add(e.clone());
}

for(Fruit e: copyOfFruits) {
    System.out.println(System.identityHashCode(e));
}

/**** 출력결과 *****

328638398
1789550256
3447021
440434003

--> 각 원소가 다른 주소값을 가진다
--> 배열의 원소가 다른 객체를 참조하고 있으며 이는 deep copy임을 의미한다
*****************/