Java オブジェクトのclone 概要

2009/06/02 17:18Update
TAGS: Java | クローン | コピー | 複製 | clone()

Java プログラミングを行う際、同じ型のオブジェクトからオブジェクトへ値の複製処理をしたい時はたまたまあります。setter/getterメソッドで一個一個セットするのも一つの手ですが、値が多くなると、すごく煩雑です。そこで、Java clone(クローン)技術を利用すれば、簡単にできます。

はじめに


そもそも、Java cloneとは何でしょうか。
次の例からみてみます。

Test.java
public class Test {
    public void someMethod() {
        super.clone();
    }
}

明らかに、clone()というメソッドはどこでも定義されていないし、Java IDEやコマンドラインから上のファイルをコンパイルしてみると、エラーにならないことを気づいたでしょうか。
super.clone()は何でしょう?

Java言語は、デフォルトではすべてのクラスはjava.lang.Objectから継承しているとみなされます。なるほど、superはObjectのことで、clone()はObjectクラスのメソッドですね。


Java言語は、java.lang.Object#clone()を通して、オブジェクトのクローン機能をサポートします。
しかし、そのままclone()メソッドを利用しようとしてもクローンできません。

Java clone()でオブジェクトのクローン


まず、以下の例から見てみます。

public class TestClone {
    public static void main(String[] args) {
        MyClone myClone1 = new MyClone("clone1");
        
        MyClone myClone2 = (MyClone)myClone1.clone();
        
        if (myClone2 != null) {
            System.out.println(myClone2.getName());
            System.out.println("myClone2 equals myClone1: " + myClone2.equals(myClone1));
        } else {
            System.out.println("Clone Not Supported");
        }
    }

}


class MyClone {
    private String name;

    public MyClone(String name) {
        this.name = name;
    }
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    
    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            return null;
        }
    }
}


実行:
C:\clone>javac *.java
C:\clone>java TestClone
Clone Not Supported
C:\clone>
結果で示したとおり、CloneNotSupportedException が投げられ、クローン機能がサポートされていません。

以下の手順で、クローン機能を有効することができます。
1)Object#clone()のオーバーライド。
protected Object clone() throws CloneNotSupportedException

外部クラスからも呼ばれるようにするため、protected修飾子をpublicに変換する必要があります。

2)java.lang.Cloneableインターフェースの実装。
Cloneableは、「クローン機能をサポートするよ」とのことをJavaに知らせるために、ただの空のインタフェースです。



なので、上のサンプルのMyCloneクラス定義を以下のように変更するだけで、クローン機能を持たせることができます。
class MyClone implements Cloneable {
    ...//その他 そのまま・・変更なし
}


実行:
C:\clone>javac *.java
C:\clone>java TestClone
clone1
myClone2 equals myClone1: false
C:\clone>
実行結果からみますと、
1)2つオブジェクトのフィールド値は同じ値である(myClone1.name = myClone2.name = "clone1")
2)それぞれ違うインスタンスである(myClone1≠myClone2)
であることをわかりました。

まとめ


クラスAはクローン機能を提供したい場合、java.lang.Cloneableインタフェースを実装し、java.lang.Object#clone()をオーバーライドすればよい。
public class A extends Cloneable {
    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            //throw (new InternalError(e.getMessage()));
            return null;
        }
    }
}


参考資料


java.lang.Object Javadoc(API仕様)

有关作者
Syboos.jp編集長システム設計や開発、保守運営などを行ってます。オープンソース技術に興味があります。

Sponsored Link


Comments

用户名 (required)

Email (will not be published) (required)

URL

Evaluation