프로그래밍/Java, Android

안드로이드나 자바에서 clone() 메소드 구현하기

당근천국 2011. 4. 7. 15:43
참고 : 용식( http://devyongsik.tistory.com/173)님의 글을 참고하여 작성 하였습니다.

자바(java)나 안드로이드(android), 닷넷( C#.net, VB.net, WPF ) 등의 객체지향 언어를 사용하다보면 필이 만나게 되는 문제가 바로 클론입니다.
원례는 클론을 안쓰고 하는것이 좋으나 상황적으로 클론아니면 답이 없을때가 있저 ㅡ.-;;;;


 
1. 클론이 없다면?
객체지향에서 클론은 메우 중요합니다.

대부분 무심결에 오브젝트를 생성해서 사용하지만 이렇게 생성해서 사용하는 오브젝트를 메모리에 어떻게 넣는 문제는 중요합니다.
일반적으로 new를 통해 생성자를 호출해여 오브젝트를 생성하면 자동으로 새로운공간에 새로운객체가 생성됩니다.
하지만 단순이 대입연산자(=)를 이용하면 메모리만 참조할뿐 그 객체는 새로운 녀석이 아니저.

이런 구조가 됩니다.

그림에서 보면 mC를 호출해도 objTemp1.A와 objTemp2.A 는 같은 값이 나옵니다. 같은 객체를 참조하기때문이저.
평상시에는 별문제가 되지 않지만 객체 자체를 빽업한다거나 할 일이 생기면 문제가 됩니다.
빽업한 겍체가 기존 객체랑 연결되있으니까 말이저 ㅎㅎㅎ

그럴때 쓰는 것이 클론입니다.


 
2. 클론이 있을때

클론메소드를 이용하면 기존 객체가 복제되어 새로운 메모리에 올라 갑니다.



mC를 호출해보면 objTemp1.A는 0이 출력되고 objTemp2.A에서는 1이 출력됩니다.

자바에서 제공하는 대부분의 오브젝트들은 클론메소드를 제공합니다. 하지만 직접만든 클래스나 오브젝트에 클론을 구현할 일을 그렇게 많지 않습니다. 객체를 보존하고 사용하는데 전역선언을 한다거나 생성자를 이용해 생성해놓고 내용을 백업한다던가 하는 방법으로 데이터를 보존할수 있는 방법이 많기 때문입니다.

그런데 다량의 데이터나 오브젝트들을 관리하는 클래스라면 클론이 편하저.(그래도 복제하는 코드 직접 구현해야 합니다. ㅜㅡ 좀 있다 자세이 이야기 하겠습니다.)
물론 성능 이슈가 있긴 하지만 말이저 ㅡ.-;


 
3. 클론을 구현하자

일단 클론을 구현하기 위해서는 Cloneable도구를 받아와야 합니다.

그리고 public Object clone()를 오버라이딩(재정의) 해야 합니다.


public class claCloneTest  implements Cloneable
{
    Object objA = null;
    String strData;

    public claCloneTest()
    {
        objA = new Object();
    }

    /**
    * 이 객체의 복제품을 리턴한다.
    */
    public Object clone()
    {
        //내 객체 생성
        Object objReturn;

        try 
        {
            objReturn = super.clone();
            return objReturn;
        } 
        catch (CloneNotSupportedException e) 
        {
            e.printStackTrace();
            return null;
        }  

    }//end clone
}//end class

이렇게 클론을 구현했습니다.
어라 그런데 써보면 이상합니다.
objA 가 재대로 복제 되지 않습니다!!


 
4. 클론은 만능이 아니다.
위 예제대로 만들어서 해보면 objA가 재대로 복제되지 안았음을 알수 있습니다.
이것은 객체를 복재할때 객체안에 있는 객체는 메모리주소가 복제 되기때문이저.
객체가 아닌 변수의 경우 이런현상이 없는데 이런 클론을 닷넷에서는 '가벼운 복제'라고 하더군요 ㅡ,.ㅡ;;
 


그림을 보면 클론은 했는데 내부에 있는 객체의 주소는 기존 객체가 가지고 있는 객체에 연결되있습니다.


그렇기때문에 이 현상을 막기위에서는 클래스 안에 있는 모든 객체도 clone()에서 클론하여 가저올 필요가 있습니다.


 
5. 클론을 완벽하게 만들자

이 예제에서는 Object형을 써서 그렇지만 다른 객체의 경우 클론이 지원됩니다.
이 예제에서는 Object형이 클론을 지원한다는 가정을 하고 코드를 작성합니다.
만약 클래스안에 생성한 객체가 클론을 지원하지 않는다면 그 객체에서도 따로 클론을 구현해 주어야 합니다.

/**
* 이 객체의 복제품을 리턴한다.
*/
public Object clone()
{
    //내 객체 생성
    Object objReturn;

    try 
    {
        objReturn = super.clone();
        ((claCloneTest)objReturn).objA = this.objA.clone();
        return objReturn;
    } 
    catch (CloneNotSupportedException e) 
    {
        e.printStackTrace();
        return null;
    } 
}//end clone

이제 해보면 재대로 작동됩니다.



 
6. 안드로이드에서 가로세로 전환시 엑티비티가 초기화 되는 현상
이 클론이 유용한 경우중에 하나가 안드로이드에서 엑티비티가 초기화 되는 현상에서 객체를 빽업 해야 할때 입니다.( 참고 : 자로세로 쿼티자판 열때 일어나는 재시작 현상  ) 객체를 그냥 참조할경우 엑티비티가 재시작되면서 객체가 날아가 null이되거나 에러가 납니다.


7.클론을 지원하지 않는다면?
클론을 지원하지 않는다면 해당 오브젝트 내부의 모든 데이터를 한땀 한땀 저장해야 합니다.
해당객체를 new로 생성한후 데이터를 하나씩 복사해야 합니다.

중간에 클론을 지원하지 않는 외부오브젝트가 있으면 복제가 불가능 할수도 있습니다.
이런경우 겉으로 보이는 데이터만 빽업이 되기 때문이죠-_-;;

닷넷에서도 마찬가지 입니다.