전공/객체지향프로그래밍

[객체지향프로그래밍][Java] Object Cloning

Campus Coder 2023. 6. 7. 17:10
728x90
반응형

clone() of Object

함수 원형

protected Object clone() throws CloneNotSupportedException

 

  • Shallow Copy
    • 객체를 복제할 때, 원본 객체와 복제 객체는 동일한 객체를 참조
    • 즉, 객체 내부에 참조 타입 필드가 있는 경우, 해당 필드의 참조는 동일하게 유지
    • 변경이 한쪽 객체에 영향을 미칠 수 있음

 

  • Deep Copy
    • 객체를 복제할 때, 원본 객체와 복제 객체는 서로 독립적인 객체를 참조
    • 즉, 참조 타입 필드의 복사본도 생성되어 변경이 한 쪽 객체에 영향을 주지 않음

 

  • Cloneable 인터페이스
    • Cloneable 인터페이스는 객체가 복제 가능함을 나타내기 위해 구현해야 함
    • 이 인터페이스를 구현하지 않은 객체는 clone() 메서드를 호출할 때 CloneNotSupportedException 예외 발생

 

  • clone() 메서드
    • clone() 메서드는 객체를 복제하여 복제된 객체를 반환
    • 접근 지정자 protected이므로, 복제를 위해 해당 클래스에서 public으로 오버라이딩
    • 반환 타입은 Object이므로, 필요에 따라 캐스팅

 

  • clone() 메서드의 오버라이딩
    • 일반적으로 super.clone()을 호출하여 얕은 복사를 수행한 뒤
    • 필요에 따라 참조 타입 필드에 대해 깊은 복사를 수행
    • 리턴 타입을 복사한 객체 타입으로 바꿀 수 있음

 

예시 1

class Point implements Cloneable { // class Point만 쓰면 예외 발생
    int x, y;

    public Point(int x, int y) {
        this.x = x; this.y = y;
    }

    @Override
    public String toString() {
        return "Point(" + x + "," + y + ")";
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        Object o = super.clone(); // 객체 복제
        System.out.println(o.getClass().getName());
        return o;
    }

}

public class Main {
    public static void main(String[] args) {
        Point p1 = new Point(2, 4);
        System.out.println(p1);
        try {
            Point p2 = (Point)p1.clone();
            System.out.println(p2);
            System.out.println(p1 == p2 ? true : false); // 서로 다른 객체면 false
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}
Point(2,4)
Point
Point(2,4)
false

 

예시 2

class Point implements Cloneable {
    int x, y;

    public Point(int x, int y) { this.x = x; this.y = y; }

    @Override
    public String toString() { return "Point(" + x + "," + y + ")"; }

    @Override
    public Point clone() throws CloneNotSupportedException {  // 리턴 타입 Point
        return (Point) super.clone();
    }
}

class Circle implements Cloneable {
    Point center;
    int radius;

    Circle(Point center, int radius) {
        this.center = center;
        this.radius = radius;
    }

    void setCenter(int x, int y) {
        this.center.x = center.y = y;
    }

    void setRadius(int radius) {
        this.radius = radius;
    }

    @Override
    public String toString() {
        return "Circle(center=" + center + "radius=" + radius + ")";
    }

    @Override
    public Circle clone() throws CloneNotSupportedException { // 리턴 타입 Circle
        Circle c = (Circle) super.clone(); // 얕은 복사
        c.center = center.clone();         // 필드의 객체까지 복사하므로 깊은 복사가 됨
        return c; // 깊은 복사 리턴
    }
}

public class Main {
    public static void main(String[] args) {
        try {
            Circle c1 = new Circle(new Point(3, 4), 2);
            System.out.println(c1);
            Circle c2 = c1.clone(); // 리턴 타입 변경으로 인해 캐스팅 불필요
            System.out.println(c2);

            c2.setCenter(30, 40); // 깊은 복사이므로 c1값은 바뀌지 않음
            c2.setRadius(20);     // 깊은 복사이므로 c1값은 바뀌지 않음
            System.out.println(c1); 
            System.out.println(c2);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}
Circle(center=Point(3,4)radius=2)
Circle(center=Point(3,4)radius=2)
Circle(center=Point(3,4)radius=2)
Circle(center=Point(40,40)radius=20)
728x90
반응형