2015-12-06 10 views
10

Cloneable Javaが本質的に壊れています。特に、私の最大の問題は、メソッドそのものを定義しないメソッドの振る舞いを期待することです。したがって、Cloneableリストをトラバースする場合は、定義された動作にアクセスするためにリフレクションを使用する必要があります。しかし、Java 8では既定のメソッドが用意されていますが、今度は、にデフォルトのclone()メソッドがない理由を尋ねます。Javaでクローン可能なデフォルトのクローン()がない理由8

私はなぜinterfaces cannot default Object methodsだと理解していますが、これは明示的な設計上の決定であり、例外があります。

私は一種のObject.clone()を卑下してのようなものに、その内部のコードを変更する想像:

if(this instanceof Cloneable) { 
    return ((Cloneable) this).clone(); 
} 
else { 
    throw new CloneNotSupportedException(); 
} 

そしてclone()Cloneableのデフォルトの方法として、そのことを行うことになりどんな魔法に移動。これはまだ実際にはclone()が簡単に間違って実装される可能性があることを修正するものではありませんが、それ自体の別の議論です。現在clone()をオーバーライドしますがCloneable(WHY ?!)もまだ機能的に不可能な場合(技術的には大丈夫だろう実装されていませんでした

  1. クラス:私の知る限り、まだこの変更が完全に下位互換性だろうことができますよう

    しかし、それは以前とはまったく異なっていません)。

  2. 現在clone()をオーバーライドしていますが、Cloneableを実装していたクラスは、実装上も同じように機能します。
  3. 現在、clone()をオーバーライドしていませんが、Cloneable(WHY ?!)を実装したクラスは、が完全にでない場合でも、仕様に準拠します。
  4. 反射を使用し、Object.clone()と呼ばれるものは、機能的にはまだ機能します。
  5. super.clone()は、Object.clone()を参照していても機能的には同じです。

これは言うまでもなく、Cloneableという大きな問題を解決します。面倒で実装が簡単ではありませんが、インタフェースではオブジェクト指向の巨大な問題を解決できます。

Cloneableを実装している唯一の問題は、clone()を上書きする義務がありませんが、これは前と同じです。

これは内部的に説明されていますが、決して実現できませんでしたか?もしそうなら、なぜですか?インターフェイスがデフォルトのObjectメソッドを使用できないという理由で、Cloneableを継承するすべてのオブジェクトがclone()を予期しているので、この場合例外を作成するのは意味がありませんか?

+5

「Cloneable」がとても壊れていて、修正する価値がないと(公式ソースから)どこかで読んでいることを覚えています。しかし、あなたのデフォルトのメソッドの問題の1つは、 'this'を使うことは難しいことです。 – Tunaki

+5

本質的に、@就活が言っていることは正しいです。このようなフープジャンプの複雑さに対する復帰は、そこにはなかった。私たちは{時間、努力、複雑さ}予算を他の分野に投資してより多くの価値を生み出しました。 –

+1

このような 'default'メソッドの作成には意味がありません。 'java.lang.Object'にメソッドがあり、' interface'に同じ名前と署名の 'default'メソッドがある場合、' java.lang.Object'で宣言されたメソッドは未修飾呼び出しのために勝ちます。 'java.lang.Object'のメソッドが' protected'のままであれば、 'Cloneable'実装は' public'メソッドを再宣言するよう強制されますが、 'public'に変更すると既存の実装を変更する必要があります。言い換えれば、結果は 'Cloneable'インタフェースで' abstract clone() 'メソッドを定義することと変わりありません。 – Holger

答えて

6

あなたの質問は多少広範で議論が増えていますが、私はこの問題についていくつか明言することができます。

有効なJava™で、Joshua Blochは状況についてかなりの説明をします。彼は、Cloneableインタフェースは へのオブジェクトのミックスインのインタフェースとして意図されていたCloneable

の背後にある歴史のビットで開きますが、彼らはクローニングを可能することをアドバタイズします。残念ながら、この目的には役立たない。主な欠点は、クローンメソッドが不足していることと、Objectのクローンメソッドが保護されていることです。リフレクションに頼ることなく、単にCloneableを実装しているため、オブジェクトのクローンメソッドを呼び出すことはできません。

及び[Cloneableを】推論

に続くオブジェクトの保護されたクローンの実装の挙動を決定する:クラスがCloneable、オブジェクトのcloneメソッドは、オブジェクトのフィールドごとのコピーを返す実装する場合。これは、インタフェースの非常に非典型的な使用であり、エミュレートされるものではありません。通常、インターフェースを実装すると、クラスがクライアントに対して何をできるかについての情報が得られます。 Cloneableの場合、スーパークラスの保護されたメソッドの動作を変更します。

Cloneableインタフェースを実装するクラス上の任意の効果を持っているのであれば、 クラスとそのスーパークラスのすべてはかなり複雑な法的強制力のない、と 薄く文書化されたプロトコルに従わなければなりません。結果として得られるメカニズムはextralinguisticです。コンストラクタを呼び出さずにオブジェクトを作成します。

あり、このに入る多くの詳細がありますが、ただ一つの問題に注意すること:

クローンアーキテクチャが変更可能なオブジェクトを参照する最後のフィールドの通常の使用と互換性がありませんが。

これは、インターフェイス内でdefaultメソッドをクローン化することに反対する理由で十分だと思います。正しく実装するのは非常に複雑です。

5

私の経験はおそらく主流ではありませんが、clone()を使用して現在のデザインCloneableをサポートしています。おそらく、代わりに注釈として使用する方がよいでしょうが、注釈の前には長めに表示されるCloneableがあります。私の意見は、Cloneableは低レベルのものであり、誰もobj instanceof Cloneableのような何かを行うべきではないということです。いくつかのビジネスロジックでCloneableを使用している場合は、clone()を公開してすべてのビジネスロジックオブジェクトに実装する独自のインターフェイスまたは抽象クラスを宣言する方がはるかに優れています。場合によっては、実際にclone()を公開したくない場合がありますが、clone()を内部的に使用する独自のメソッドを作成することがあります。

たとえば、作成後に名前を変更することはできないが、名前を新しい名前で複製できるようにする名前付きオブジェクトの階層があるとします。あなたはこのようないくつかの抽象クラスを作成することができます。ここでは

public abstract class NamedObject implements Cloneable { 
    private String name; 

    protected NamedObject(String name) { 
     this.name = name; 
    } 

    public final String getName() { 
     return name; 
    } 

    public NamedObject clone(String newName) { 
     try { 
      NamedObject clone = (NamedObject)super.clone(); 
      clone.name = newName; 
      return clone; 
     } 
     catch(CloneNotSupportedException ex) { 
      throw new AssertionError(); 
     } 
    } 
} 

をあなたはCloneableを実装していても、あなたはclone()を使用したいのですが、公にそれを公開する必要はありません。代わりに、別の名前でクローンを作成する別の方法を提供します。だから公開clone()Cloneableに入れると、クラスのパブリックインターフェイスが不必要に汚染されます。

Cloneableを使用する別のケースは、Spliterator.trySplit()の実装です。指定された数の定数オブジェクトを返す単純なスプライテータのimplementationを参照してください。それは4つの特殊化(オブジェクト、ints、longsとdouble)がありますがclone()のおかげで、私はtrySplit()をスーパークラスに1回しか実装できません。繰り返しますが、私はclone()を公開したくありません。私はそれを自分で使いたいだけです。

結論として、Cloneableインターフェイスにclone()メソッドを持たないのは、私がそれを公開したいかどうかを決定することができるので、実際はもっと柔軟です。

+0

@Holger、それは 'protected clone()'とは違ってパラメータをとる別の方法です。 –