Creates and returns a copy of this object. 
The precise meaning of "copy" may depend on the class of the object.

자바 공식문서에서는 Object 객체의 clone() 메서드를 다음과 같이 설명하였다.

객체의 복사본을 생성하고 반환한다. 복사 의 정확한 의미는 객체의 클래스마다 다르다.

https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Object.html#clone()

clone() 메서드 사용법

그럼 clone() 을 이용하여 객체를 복사하려면 어떻게 해야할까? Object 객체가 가지고 있는 clone() 메서드를 오버라이딩하여 원하는 객체에 clone() 메서드를 사용할 수 있다. clone() 메서드를 오버라이딩하려면 다음과 같은 과정이 필요하다.

public class Member implements Cloneable {
    private String name;
    private int age;

    @Override
    public Member clone() {
        try {
            return (Member) super.clone();
        } catch (CloneNotSupportedException e) {
            // Cloneable을 구현했기 때문에 이 블록이 실행되는 일은 없다.
            return null;
        }
    }
}

1. Cloneable 인터페이스 구현

복제를 허용한 객체임을 명시하는 인터페이스이다. 해당 인터페이스를 구현하지 않고 clone() 메서드를 호출하면 CloneNotSupportedException 예외가 발생한다.

2. CloneNotSupportedException 캐치

Cloneable 인터페이스를 구현했더라도 CloneNotSupportedException 예외를 잡아주어야 한다. checked Exception 이기 때문이다.

3. 반환 객체 타입 변경

복제하려는 객체의 타입은 Obejct 는 아닐 것이다. 원하는 객체 타입으로 수정해주어야 올바른 타입의 객체가 반환된다.

public class CloneTest {
    public static void main(String[] args) {
        Member member1 = new Member("wayne", 31);
        Member member2 = member1.clone();

        System.out.printf("%s, name=%s, age=%d\\n", member1, member1.getName(), member1.getAge());
        System.out.printf("%s, name=%s, age=%d\\n", member2, member2.getName(), member2.getAge());
    }
}

Untitled

Member 객체를 clone() 메서드를 활용하여 복사하였다. 출력된 해시코드를 보면 값이 다르다. 원본 객체와는 다른 새로운 객체가 복제되어 생성됨을 나타낸다. 객체를 복사하였기 때문에 객체 내부의 인스턴스 값은 동일하다.

얕은 복사

하지만 clone() 메서드에는 큰 단점이 있다. clone() 을 이용하여 복사한 객체는 얕은 복사 가 된 객체이다. 얕은 복사란, 복사하려는 객체는 새로 생성한 객체이나 기존 객체가 가지고 있던 내부 필드 또는 객체는 동일한 객체를 사용한다.

public class Member implements Cloneable {
    private String name;
    private int age;
    private Address address;

    @Override
    public Member clone() {
        try {
            return (Member) super.clone();
        } catch (CloneNotSupportedException e) {
            // Cloneable을 구현했기 때문에 이 블록이 실행되는 일은 없다.
            return null;
        }
    }
}

위의 코드처럼 복사하려는 객체가 참조형 타입의 값을 가지고 있는 경우라면 문제가 발생할 수도 있다.