18

配列のディープコピーを正しく実行することについて読んでいましたが、#clone()実装方法について混乱していました。これはjava.lang.Objectクラスのメンバーですが、javadocs を読むと:

まず、このオブジェクトのクラスがインターフェース Cloneable を実装していない場合、CloneNotSupportedException がスローされます。

cloneでは、そもそもなぜそこでメソッドを定義するのでしょうか? 確かに、インターフェイスが存在する場合にのみメソッドを使用できる場合は、メソッドをインターフェイスに配置します。Cloneableインターフェイス自体は空です。cloneこれは、メソッドの使用が合法であることを確認するために Java によって使用される単なるマーカー インターフェイスです。

このようにすると、型の安全性を確保するためにジェネリックを使用する機能も削除されます。

class Foo implements Cloneable { // Valid.
    @Override
    public Object clone() throws CloneNotSupportedException {
        // ...
    }
}

class TypeSafeFoo implements Cloneable<TypeSafeFoo> { // Not valid.
    @Override
    public TypeSafeFoo clone() throws CloneNotSupportedException {
        // ...
    }
}

なぜJavaはこのようにしたのですか?正当な理由があると確信していますが、それを理解できないようです。

4

3 に答える 3

27

Java の複製規約では、各clone実装が最初に から複製されたインスタンスを取得する必要があることが規定されていますsuper.clone()。これにより、常に への呼び出しで終了するチェーンが作成され、そのメソッドには、Java オブジェクトを表すObject.clone下層の raw のバイナリ コピーを作成する「魔法のような」ネイティブ レベル コードが含まれます。structこのメカニズムが存在しない場合、cloneポリモーフィックにはなりません。Object.cloneメソッドは、呼び出されたクラスのインスタンスを生成します。これは、ネイティブ コードなしでは再現できません。

これが、このObject.clone方法が避けられなかった理由です。メソッドを含めることもCloneable できましたが、句cloneに関する問題が発生します。throws現状では、宣言された例外なしで自由に宣言することもclone、任意の例外を宣言することもできます。メソッドがインターフェイスで既に宣言されている場合、この柔軟性は実現できません。

Generics はクローン作成にはほとんど役に立たないことに注意しprotected T clone()ObjectくださいTJavaユニバースのすべてのクラスObject<T>をそれ自体でパラメーター化する必要があり、強制する必要がありますか?これは、この半非推奨のメカニズムを少しだけうまく機能させるためですか? このコードは完全に合法であることにも注意してください。

public class TheMightyOne implements Cloneable {
   @Override public TheMightyOne clone() {
     return (TheMightyOne) super.clone();
   }
}

あなたはそれを呼び出すことができます:

TheMightyOne one = new TheMightyOne();
TheMightyOne two = one.clone(); // do downcasts needed
于 2012-12-02T15:23:42.600 に答える
0

clone()メソッドは不要です。すべてのオブジェクトがObject.cloneリフレクトによってメソッドを呼び出すことができるため、オブジェクトを複製できるかどうかは、インターフェイスを実装するかどうかによって異なりCloneableます。これはセキュリティ上の理由によるものです。Cloneableこのユーティリティで実装するオブジェクトを簡単に複製できます。

@SuppressWarnings("unchecked")
public static <T extends Cloneable> T clone(Cloneable obj) {
    T rtn = null;
    try {
        Method method = Object.class.getDeclaredMethod("clone");
        method.setAccessible(true);
        rtn = (T) method.invoke(obj);
    } catch (Throwable t) {
        t.printStackTrace();
    }
    return rtn;
}
于 2013-06-27T09:10:52.363 に答える