Java 8では、Default Methodsと呼ばれるインターフェースでメソッドのデフォルト実装が可能です。
私は(with )interface default method
ではなく、そのようなをいつ使用するのか混乱しています。abstract class
abstract method(s)
では、デフォルトのメソッドとのインターフェースをいつ使用し、抽象クラス(抽象メソッドを含む)をいつ使用する必要があるのでしょうか。抽象クラスはそのシナリオでもまだ役に立ちますか?
Java 8では、Default Methodsと呼ばれるインターフェースでメソッドのデフォルト実装が可能です。
私は(with )interface default method
ではなく、そのようなをいつ使用するのか混乱しています。abstract class
abstract method(s)
では、デフォルトのメソッドとのインターフェースをいつ使用し、抽象クラス(抽象メソッドを含む)をいつ使用する必要があるのでしょうか。抽象クラスはそのシナリオでもまだ役に立ちますか?
回答:
抽象クラスには、デフォルトのメソッド実装(プライベート状態など)よりも多くの機能がありますが、Java 8以降では、どちらかを選択できる場合は常にdefault
、インターフェースのdefender(aka。)メソッドを使用する必要があります。
デフォルトのメソッドの制約は、特定の実装の状態を参照せずに、他のインターフェイスメソッドの呼び出しに関してのみ実装できることです。したがって、主なユースケースは、より高レベルで便利なメソッドです。
この新機能の良い点は、以前は便利なメソッドに抽象クラスを使用せざるを得なかったため、実装者を単一継承に制限していたため、インターフェイスと最小限の実装で本当にすっきりとした設計ができるようになりました。プログラマーに強いられた努力。
default
Java 8にメソッドを導入する当初の動機は、既存の実装を壊すことなく、ラムダ指向のメソッドでCollections Frameworkインターフェースを拡張したいという願望でした。これは公共図書館の作成者にとってより重要ですが、同じ機能がプロジェクトでも役立つ場合があります。新しい便利さを追加するための集中化された場所が1つあり、型階層の残りの部分がどのように見えるかに依存する必要はありません。
いくつかの技術的な違いがあります。抽象クラスは、Java 8インターフェースと比較してさらに多くのことができます。
概念的には、ディフェンダーメソッドの主な目的は、Java 8に新しい機能(ラムダ関数として)が導入された後の下位互換性です。
public static final
インターフェースのフィールドを「状態」とは記述しません。このstatic
部分は、特定のインスタンスにまったく関連していないことを意味します。それらはクラスのインスタンス化に割り当てられますが、インスタンスの作成後とは異なります。
これについては、この記事で説明しています。forEach
コレクションについて考えてください。
List<?> list = …
list.forEach(…);
forEachはまだインターフェイスで
java.util.List
も 宣言されてjava.util.Collection
いません。明らかな解決策の1つは、既存のインターフェースに新しいメソッドを追加し、JDKで必要な場所に実装を提供することです。ただし、いったん公開されると、既存の実装を壊さずにメソッドをインターフェースに追加することは不可能です。デフォルトのメソッドがもたらす利点は、新しいデフォルトのメソッドをインターフェースに追加できるようになり、実装を壊さないことです。
AbstractList::forEach
スローしUnsupportedOperationException
ます。
これら2つはまったく異なります。
デフォルトのメソッドでは、状態を変更せずに既存のクラスに外部機能を追加します。
また、抽象クラスは通常のタイプの継承であり、拡張を目的とした通常のクラスです。
この記事で説明したように、
Java 8の抽象クラスとインターフェース
デフォルトメソッドを導入した後、インターフェースと抽象クラスは同じように見えます。ただし、Java 8ではまだ異なる概念です。
抽象クラスはコンストラクタを定義できます。それらはより構造化されており、状態を関連付けることができます。対照的に、デフォルトのメソッドは、特定の実装の状態を参照せずに、他のインターフェースメソッドを呼び出すという観点でのみ実装できます。したがって、両方が異なる目的で使用され、2つの間の選択は、実際にはシナリオのコンテキストに依存します。
あなたのクエリについて
では、デフォルトのメソッドとのインターフェースをいつ使用し、いつ抽象クラスを使用する必要があるのでしょうか。抽象クラスはそのシナリオでもまだ役に立ちますか?
Java ドキュメントは完璧な答えを提供します。
抽象クラスとインターフェースの比較:
抽象クラスはインターフェースに似ています。それらをインスタンス化することはできません。また、実装の有無にかかわらず宣言されたメソッドが混在している場合があります。
ただし、抽象クラスを使用すると、静的および最終ではないフィールドを宣言し、パブリック、保護、およびプライベートの具象メソッドを定義できます。
インターフェースを使用すると、すべてのフィールドは自動的にpublic、static、finalになり、宣言または定義した(デフォルトのメソッドとして)すべてのメソッドはpublicになります。また、抽象クラスであるかどうかに関係なく、拡張できるクラスは1つだけですが、任意の数のインターフェイスを実装できます。
それぞれの使用例は、以下のSEポストで説明されています。
抽象クラスはそのシナリオでもまだ役に立ちますか?
はい。彼らはまだ便利です。それらは非静的で非最終的なメソッド と属性(publicに加えてprotected、private)を含むことができますが、これはJava-8インターフェースでも不可能です。
抽象クラスとインターフェースのどちらかを選択する場合は常に、デフォルトの(ディフェンダーまたは仮想拡張とも呼ばれる)メソッドを常に(ほぼ)優先する必要があります。
Collection and AbstractCollection
です。次に、インターフェース自体にメソッドを実装して、デフォルトの機能を提供する必要があります。インターフェイスを実装するクラスは、メソッドをオーバーライドするか、デフォルトの実装を継承するかを選択できます。デフォルトのメソッドのもう1つの重要な使用法はinterface evolution
です。次のようなクラスBallがあるとします。
public class Ball implements Collection { ... }
Java 8では、新しい機能が導入されました。stream
インターフェイスに追加されたメソッドを使用してストリームを取得できます。stream
デフォルトのメソッドでない場合、Collection
インターフェースのすべての実装は、この新しいメソッドを実装していないため、壊れています。デフォルト以外のメソッドをインターフェイスに追加することはできませんsource-compatible
。
ただし、クラスを再コンパイルせず、このクラスを含む古いjarファイルを使用するとしますBall
。クラスはこの不足しているメソッドなしで正常にロードされ、インスタンスを作成でき、すべてが正常に動作しているようです。しかし、プログラムがstream
インスタンスでメソッドを呼び出すBall
と、が取得されAbstractMethodError
ます。したがって、メソッドをデフォルトにすると、両方の問題が解決しました。
Javaインターフェースのデフォルトのメソッドは、インターフェースの進化を可能にします。
既存のインターフェースを前提として、古いバージョンのインターフェースとのバイナリ互換性を損なうことなくメソッドを追加したい場合は、デフォルトまたは静的メソッドを追加するという2つの選択肢があります。実際、インターフェースに追加された抽象メソッドは、このインターフェースを実装するクラスまたはインターフェースによって実装される必要があります。
静的メソッドはクラスに固有です。デフォルトのメソッドは、クラスのインスタンスに固有です。
デフォルトのメソッドを既存のインターフェースに追加する場合、このインターフェースを実装するクラスおよびインターフェースは、それを実装する必要はありません。彼らはできる
トピックの詳細はこちら。
それは古い質問ですが、私の意見も聞かせてください。
抽象クラス:抽象クラス内では、子クラスに必要なインスタンス変数を宣言できます
インターフェース:インターフェース内では、すべての変数は常に静的であり、最後にインスタンス変数を宣言することはできません
抽象クラス:抽象クラスはオブジェクトの状態について話すことができます
インターフェース:インターフェースはオブジェクトの状態について話すことはできません
抽象クラス:抽象クラス内でコンストラクタを宣言できます
インターフェース:インターフェースの内部で
は、コンストラクターの目的はインスタンス変数を初期化することなので、コンストラクターを宣言できません。インターフェイスにインスタンス変数を含めることができない場合、そこでコンストラクタが必要になるのはなぜですか。
抽象クラス:抽象クラス内では、インスタンスと静的ブロックを宣言できます
インターフェース:インターフェースにインスタンスブロックと静的ブロックを含めることはできません。
抽象クラス:抽象クラスはラムダ式を参照できません
インターフェース:単一の抽象メソッドを持つインターフェースはラムダ式を参照できます
抽象クラス:抽象クラス内で、OBJECT CLASSメソッドをオーバーライドできます
インターフェース:インターフェース内のOBJECT CLASSメソッドをオーバーライドすることはできません。
私は次のことに注意して終わります:
インターフェースのデフォルトのメソッドの概念/静的メソッドの概念は、実装クラスを保存するためだけのものであり、意味のある有用な実装を提供するためのものではありません。デフォルトのメソッド/静的メソッドは、ダミーの実装の一種であり、「使用したい場合、または実装クラスでそれらをオーバーライドできる場合(デフォルトのメソッドの場合)」、したがって、インターフェースの新しいメソッドがいつでも実装クラスに新しいメソッドを実装する必要がなくなります。追加されます。したがって、インターフェースを抽象クラスと同じにすることはできません。
Java 8では、インターフェイスは抽象クラスのように見えますが、次のような違いがある場合があります。
1)抽象クラスはクラスであるため、Javaのインターフェースの他の制限に制限されません。たとえば、抽象クラスは状態を持つことができますが、Javaのインターフェースで状態を持つことはできません。
2)デフォルトのメソッドを持つインターフェースと抽象クラスのもう1つの意味上の違いは、抽象クラス内にコンストラクターを定義できるが、Javaのインターフェース内にコンストラクターを定義できないことです。
他の回答で述べたように、コレクションフレームワークに下位互換性を提供するために、インターフェイスに実装を追加する機能が追加されました。下位互換性を提供することが、実装をインターフェイスに追加する唯一の正当な理由であると私は主張します。
それ以外の場合、インターフェースに実装を追加すると、インターフェースが最初に追加された理由に関する基本法則に違反することになります。Javaは、複数の継承を可能にするC ++とは異なり、単一の継承言語です。インターフェイスは、多重継承に伴う問題を引き起こさずに、多重継承をサポートする言語に付属する型付けの利点を提供します。
より具体的には、Javaは実装の単一継承のみを許可しますが、インターフェースの複数継承を許可します。たとえば、以下は有効なJavaコードです。
class MyObject extends String implements Runnable, Comparable { ... }
MyObject
継承は1つだけですが、3つのコントラクトを継承します。
実装の多重継承には多くの厄介な問題が伴うため、Javaは実装の多重継承を渡しましたが、これはこの回答の範囲外です。実装の多重継承の問題なしにコントラクトの多重継承(別名インターフェイス)を可能にするために、インターフェイスが追加されました。
私の主張を裏付けるために、ここに本「Javaプログラミング言語、第4版」からのケン・アーノルドとジェームズ・ゴスリングの引用があります:
単一継承は、いくつかの有用で正しい設計を妨げます。多重継承の問題は、実装の多重継承から生じますが、多くの場合、多重継承は、多数の抽象的なコントラクトとおそらく1つの具体的な実装を継承するために使用されます。実装を継承せずに抽象コントラクトを継承する手段を提供することで、複数の実装の継承の問題なしに、複数の継承の型付けの利点を実現できます。抽象コントラクトの継承は、インターフェイスの継承と呼ばれ ます。Javaプログラミング言語は、
interface
型を宣言できるようにすることで、インターフェースの継承をサポートします
まずは開閉原理を考えてください。インターフェースのデフォルトのメソッドはそれを違反します。これはJavaの悪い機能です。それは悪いデザイン、悪いアーキテクチャ、低いソフトウェア品質を奨励します。デフォルトのメソッドを完全に使用しないことをお勧めします。
いくつか自問してみてください。なぜメソッドを抽象クラスに入れられないのでしょうか。次に、複数の抽象クラスが必要ですか?次に、クラスが何を担当するかを考えます。単一のクラスに配置するすべてのメソッドが本当に同じ目的を果たしていることを確信していますか?いくつかの目的を区別して、クラスをいくつかのクラスに分割し、それぞれの目的のために独自のクラスを作成することができます。