Cloneableが非推奨にならないのはなぜですか?


139

CloneableJavaのインターフェースが壊れていることは一般的に理解されています。これには多くの理由がありますが、これについては触れません。他の人はすでにそれをしました。また、Javaアーキテクト自身の立場でもあります

したがって、私の質問は次のとおりです。なぜまだ非推奨になっていないのですか?コアJavaチームが破損していると判断した場合は、廃止も検討しているはずです。そうすることに対する彼らの理由は何ですか(Java 8ではまだ非推奨ではありません)?


41
この質問は「主に意見に基づく」ものではありません。理由についての意見以上のものを何も持っていない人は、答える資格がないだけです。ただし、ここで信頼できる回答を得られる可能性はほとんどありません。また、あなたの質問があなたが抱えている解決可能な問題に関するものではないことも事実なので、それは少なくとも境界線外のトピックです。
Marko Topolnik、2014年

6
@MarkoTopolnik私は世界中に信頼できる答えを提供できる人がいることに同意しますが、私がここで適用するテストだとは思いません。閉鎖理由には、「この質問への回答ほとんど完全に意見に基づく傾向がある」と述べています。私たちが非常に幸運にならない限り、私はここがそうであろうと思います。
Duncan Jones

2
Oracleから非推奨にする「方法とタイミング」はここにあります...(docs.oracle.com/javase/6/docs/technotes/guides/javadoc/…)非常に意見を受け入れます。
Maxx

8
@ダンカン私はまだ、回答者側の規律の欠如についての私の仮定に基づいて、質問に対する判断を下すことは公正であるとは思わない。質問された理由がわからない場合、ユーザーは応答機能を悪用して問題について自分の意見を述べることはできません。
Marko Topolnik、2014年

4
@lexicoreはい、そうです---そして、あなたは彼らがそのオプションを徹底的に検討し、暗黙のうちにそれを非推奨にしない強い理由があるに違いないに違いない。彼ら自身の批判Cloneableは広く知られています。
Marko Topolnik、2014年

回答:


120

にメソッドを追加することに関して、1997年にJava Bug Databaseに提出されたバグがあるため、もはや役に立たなくなります。それは「修正しない」という決議で閉鎖され、正当化は次のとおりでした。clone()Cloneable

SunのTechnical Review Committee(TRC)はこの問題を詳細に検討し、現在のCloneableインターフェースのドキュメントを改善する以外のアクションをとらないよう推奨しました。推奨事項の全文は次のとおりです。

既存のJavaオブジェクトの複製APIには問題があります。java.lang.Objectには保護された「clone」メソッドがあり、インターフェースjava.lang.Cloneableがあります。意図は、クラスが他の人に複製を許可したい場合は、Cloneableインターフェースをサポートし、デフォルトの保護された複製メソッドをpublic複製メソッドでオーバーライドする必要があるということです。あいにく、都合の悪いことに時間の経過とともに失われてしまう理由により、Cloneableインターフェースはcloneメソッドを定義していません。

この組み合わせにより、かなりの混乱が生じます。一部のクラスはCloneableをサポートしていると主張していますが、誤ってcloneメソッドのサポートを忘れています。開発者は、Cloneableがどのように機能し、どのように機能するのかについて混乱しています。

残念ながら、「clone」メソッドをCloneableに追加すると、互換性のない変更になります。バイナリ互換性は失われませんが、ソース互換性は失われます。事例証拠は、実際にはクラスがCloneableインターフェースをサポートしているが、パブリッククローンメソッドを提供できないケースが多数あることを示唆しています。議論の後、互換性への影響があるため、TRCは満場一致で既存のCloneableインターフェースを変更しないことを推奨しました。

別の提案は、Cloneableの本来の意図された目的を反映するために、新しいインターフェースjava.lang.PubliclyCloneableを追加することでした。5から2の過半数で、TRCはこれを推奨しませんでした。主な懸念は、これにより、すでに混乱している画像にさらに混乱(スペルの混乱を含む!)が追加されることでした。

TRCは満場一致で、既存のCloneableインターフェイス追加のドキュメントを追加して、それがどのように使用されるかをより適切に説明し、実装者向けの「ベストプラクティス」を説明することを推奨しました

したがって、これは直接非推奨ではありませんが、Cloneableを「非推奨」にしない理由は、Technical Review Comiteeが、既存のドキュメント修正するだけでこのインターフェースを十分に活用できると判断したためです。そして彼らはそうしました。Java 1.4までCloneableは、次のように文書化されていました。

クラスはCloneableインターフェースを実装して、Object.clone()メソッドに、そのクラスのインスタンスのフィールドごとのコピーを作成することが正当であることを示します。

Cloneableインターフェースを実装しないインスタンスのクローンを作成しようとすると、例外CloneNotSupportedExceptionがスローされます。

インターフェイスCloneableはメソッドを宣言しません。

Java 1.4(2002年2月にリリースされた)から最新版(Java 8)までは、次のようになります。

クラスはCloneableインターフェースを実装して、Object.clone()メソッドに、そのクラスのインスタンスのフィールドごとのコピーを作成することが正当であることを示します。Cloneableインターフェースを実装していないインスタンスでObjectのcloneメソッドを呼び出すと、例外CloneNotSupportedExceptionがスローされます。

慣例により、このインターフェイスを実装するクラスは、Object.clone(保護されている)をパブリックメソッドでオーバーライドする必要があります。このメソッドのオーバーライドの詳細については、Object.clone()を参照してください。

このインターフェースにはcloneメソッドが含まれていないことに注意してください。したがって、このインターフェイスを実装しているという事実だけでは、オブジェクトのクローンを作成することはできません。cloneメソッドがリフレクトで呼び出されても、成功する保証はありません。


3
そして、そのclone方法がObject最初にあった理由を知っていますか?
njzk2 14年

8
@ njzk2これはメカニズムの重要な部分です---これは、オブジェクトイメージを少しずつコピーする低レベルの言語外の魔法を実行するメソッドです。
Marko Topolnik 2014年

3
@Unheiligその魔法は、コピーコンストラクターでは複製できないものですObject#clone()。コンパイル時にクラスが認識されていなくても、元のクラスと同じクラスのインスタンスを生成します。
Marko Topolnik 2014年

4
@AVolpe:「クラスがCloneableインターフェースをサポートしているが、パブリッククローンメソッドを提供できない場合」で述べられているソースの非互換性は修正されません。特に、非パブリッククローンメソッドを提供するクラスは壊れます。
Louis Wasserman 2014年

2
素晴らしい歴史。ここにあります直接リンクバグデータベースには。そこにさらに履歴を追加し、その一部を私の回答に引用しました。
Stuart Marks

64

「なぜCloneable廃止されないのですか?」に対する短い回答 (実際、がなぜX非推奨にならないのかX)は、それらを非推奨にすることにあまり注意が払われていないことです。

最近廃止されたもののほとんどは、それらを削除する特定の計画があるため、廃止されました。例えば、addPropertyChangeListener及びremovePropertyChangeListener方法のLogManagerをされたのJava SE 8で非推奨のJava SE 9でそれらを除去する目的で(その理由は、彼らが不必要にモジュールの依存関係を複雑にしていることである。)確かに、これらのAPIは、既にされている初期のJDK 9から削除開発ビルド。(同様のプロパティ変更リスナー呼び出しもから削除されていることに注意してPack200ください。JDK-8029806を参照してください。)

そのような同様の計画がのために存在しないCloneableObject.clone()

より長い回答には、これらのAPIに起こりそうなこと、プラットフォームが非推奨になった場合にプラットフォームに発生するコストやメリット、APIが非推奨になった場合に開発者に伝えられることなど、さらなる質問についての議論が含まれます。私は最近のJavaOneの講演であるDebt and Deprecationでこのトピックを調査しました。(そのリンクでスライドが利用可能です。ビデオはこちらです。)JDK自体は、非推奨の使用法について一貫性があまりないことがわかりました。たとえば、次のようないくつかの異なる意味で使用されています。

  • これは危険であり、あなたがそれを使用することのリスクを認識する必要があります(例:Thread.stop()Thread.resume()、およびThread.suspend())。

  • これは将来のリリースで削除される予定です

  • これは時代遅れであり、別のものを使用することをお勧めします(例:のメソッドの多くjava.util.Date

これらはすべて別個の意味であり、それらの異なるサブセットは、非推奨のさまざまなものに適用されます。そして、それらのサブセットの一部は、非推奨ではないものに適用されます(ただし、非推奨にする必要があるかもしれません)。

CloneableそしてObject.clone()、彼らは設計上の欠陥を持っているし、正しく使用することは困難であるという意味で「壊れた」されています。ただし、clone()それでも配列をコピーするための最良の方法であり、複製には、慎重に実装されたクラスのインスタンスのコピーを作成するためのいくつかの限定された有用性があります。クローンの削除は互換性のない変更であり、多くのことを壊します。クローン操作は別の方法で再実装することもできますが、おそらくそれよりも遅くなりObject.clone()ます。

ただし、ほとんどの場合、コピーよりもコピーコンストラクタの方が適しています。そのCloneableため、「廃止された」または「置き換えられた」などのマークを付けるのが適切な場合があります。これは、おそらく他の場所を調べたいと開発者に伝えますが、将来のリリースで複製メカニズムが削除される可能性があることを示すものではありません。残念ながら、そのようなマーカーは存在しません。

現状では、「非推奨」は最終的には削除されることを意味しているようです-廃止された機能のほとんどが削除されたという事実にもかかわらず-したがって、クローン作成メカニズムの非推奨は保証されていないようです。おそらく将来的には、代わりのメカニズムを使用するように開発者に指示する代替のマーキングを適用することができます。

更新

バグレポートにいくつかの履歴を追加しました。初期のJVM実装者であり、JVM仕様の共著者であるフランクイェリンは、他の回答で引用されているTRC勧告の「失われた時間の中で」のコメントに応えて、いくつかのコメントをしました。ここでは関連する部分を引用しました。完全なメッセージはバグレポートにあります。

Serializableにはないのと同じ理由で、Cloneableにはメソッドがありません。Cloneableは、クラスがサポートするメソッドについて具体的に何も言わずに、クラスのプロパティを示します。

リフレクションの前に、オブジェクトの浅いコピーを作成するためのネイティブメソッドが必要でした。したがって、Object.clone()が生まれました。また、多くのクラスがこのメソッドをオーバーライドすることを望み、すべてのクラスが複製されることを望まないことも明らかでした。したがって、Cloneableはプログラマーの意図を示すために生まれました。

つまり、要するに。Cloneableの目的は、パブリックclone()メソッドがあることを示すことではありませんでした。Object.clone()を使用してクローンを作成する意思があることを示すためであり、clone()を公開するかどうかを決定するのは実装次第でした。


3
あなたがここにいる素晴らしい答えが1つあります。私は特にObject.clone()、誰もが望んでいるという理由だけで火の中に放り込むのではなく、あなたが推論してその良いところを持ち出してくれることを望んでいます。
icza 2014年

2
ただし、clone()は依然として配列をコピーするための最良の方法であり、複製には、慎重に実装されたクラスのインスタンスのコピーを作成するためのいくつかの限られた有用性があります。私は6428387の修正で印象に残りました、すべてのコードパス(clone、new / arrayCopy、Arrays.copyOf)は同じ組み込みをもたらしました。最近何か変わったことはありますか?
bestsss 2014年

2
@bestsss array.clone()必ずしも他のどの方法よりも速いとは思いません。APIの観点からは、配列を複製する最も簡単な方法です。Arrays.copyOf(array, newlen)近づきますが、これには長さパラメータが必要です。長さを変更しない場合は冗長です。
Stuart Marks

2
@Holgerはい、これは、1.1からのAPIの最初の実際の削除です。また、Thread.suspend()and Thread.stop()(引数なし)は危険であることに同意しますが、人々は実際に使用しているため、おそらく削除されず、または無条件に例外をスローするように変更されません。おそらく彼らはリスクを負うことをいとわないでしょう。プロパティ変更リスナーの問題を緩和する要素の1つは、使用頻度が非常に低いため、削除しても影響が小さいことです。
Stuart Marks

2
@Holger java.beansjava.desktop、Beanがプロパティの単なるライブラリAPIであるため、概念的には独立させることができます。残念ながら、Beans APIを掘り下げる場合、AWTには多くの依存関係があります。実装にはさらに多くの機能があります。確かにそれらを解放することは可能かもしれませんが、それを行うことは、例えば、ロギングをBeanから切り離すことよりもはるかに多くの作業のように思えます。モジュール化の取り組み全体は、これを解きほぐすことです。間違いなくもっと多くのことができますが、ジグソーはさらに時間がかかります。
Stuart Marks

-1

なぜまだ非推奨になっていないのですか?

JCPがそうするのに適していないので、そうすることは決してないかもしれないからです。それらを尋ねます。間違った場所で質問しています。

これをJava APIで維持する背後にある理由は何ですか

下位互換性の要件があるため、Java APIから何も削除されることはありません。最後に起こったのは、1996/7における1.0と1.1の間のAWTイベントモデルの変更でした。


17
それらは、(ターゲットスレッドではなく)Thread.stop(Throwable)常にUnsupportedOperationException呼び出し元にスローするようにコントラクトを変更することにより、(事実上)削除しました。
Marko Topolnik、2014年

22
同じ時期に何が起こりましたか?Thread.stop(Throwable)の機能の削除はJava 8で発生しました。とにかく、今日、主任のJavaアーキテクト自身がStack Overflowのアクティブメンバーであるため、「質問する」という無条件のアドバイスは間違っています。彼はストリーム関連の質問以外に何も答えなくても問題はありません。
Marko Topolnik、2014年

13
さらに、OPの問題は削除に関するものではなく、廃止に関するものであり、明らかに廃止がずっと続いています。
Marko Topolnik、2014年

17
@EJP私はCloneableJava APIから削除されるかどうか尋ねていません。なぜそれが実用化されないのかと尋ねています。そして、これは尋ねるのに最適な場所だと思います。
花王

5
@VaheHarutyunyan叫び声をありがとう、私はJavaアーキテクトではありません。私はOracleのJDKグループのエンジニアであり、これを維持しています。
Stuart Marks、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.