2012-12-02 5 views
10

配列のディープコピーを正しく実行していると読んでいましたが、#clone()がどのように実装されているのか混乱しました。それはjava.lang.Objectクラスのメンバーであり、そしてまだあなたがjavadocを読んでいる場合:#clone()がCloneableインターフェイスにないのはなぜですか?

まず、このオブジェクトのクラスは、インタフェース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は、このようにそれを行っていますか?彼らに正当な理由があると確信していますが、私はそれを理解しているようには見えません。

+3

実はこれは、これはクローニングが壊れたと考えられている多くの理由の一つであるジョシュア・ブロック –

+0

で言った設計上の欠陥でした。 –

答えて

14

Javaのクローニング契約では、各cloneの実装では、最初にからクローンインスタンスを取得する必要があります。これにより、常にObject.cloneの呼び出しで終了する連鎖が作成され、そのメソッドには、Javaオブジェクトを表す基になるrawのstructのバイナリコピーを作成する「魔法の」ネイティブレベルコードが含まれています。このメカニズムが存在しない場合、cloneは多態性に失敗します。Object.cloneメソッドは、呼び出されたクラスのインスタンスを生成します。ネイティブコードなしではこれを再現することはできません。

これは、Object.cloneメソッドを回避できなかった理由です。 Cloneableにはcloneメソッドが含まれていますが、throws句に関する問題が発生します。あなたの立場は、宣言されていない例外、または任意の例外を宣言することなくcloneを宣言することは自由です。この柔軟性は、メソッドがすでにインタフェースで宣言されている場合は不可能です。

ジェネリックスがクローニングにはほとんど役に立たないことを覚えておいてください。をObjectに入れてください:Tはどこですか? Object<T>が必要ですか?Javaユニバースの各クラスは、それ自体でパラメータ化されている必要がありますか?これはすべて、この半廃止されたメカニズムをちょっと改善しました。このコードは完全に合法であることに注意してもしてください:

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

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

TheMightyOne one = new TheMightyOne(); 
TheMightyOne two = one.clone(); // do downcasts needed 
+0

魔法のクローンメソッドを静的にすることで、これを避けることはできませんでしたか? 'Object.clone(Cloneable item)'です。それで 'Cloneable'を実装するものは' this'を 'Object.clone'に渡します。これはジェネリック医薬品でも簡単に機能しました。 –

4

クローンと基本フィールドのコピーを作成するには、クローンがメソッドの実装を継承する必要があります。 Cloneableクラスは階層内のどこにでも配置でき、プライマリジョブを実行するために特定のスーパークラスを拡張する必要がある場合があります。すべての可能なCloneableクラスが実装を継承できる唯一のスーパークラスはObjectです。

クローニングは、ジェネリックのかなり前に定義された。

0

clone()方法が不要で、すべてのオブジェクトは、そのオブジェクトを複製することができ、Object.cloneメソッドを呼び出すことができCloneableインターフェイスを実装するかどうかによって異なります。これはセキュリティ上の理由によるものです。あなたは、単にこのutilので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; 
} 
関連する問題