Abstactクラスとインターフェースの違い
- Java 8の抽象クラスとインターフェース
- 概念的な違い:
Java 8のインターフェースのデフォルトメソッド
- デフォルトの方法とは何ですか?
- デフォルトのメソッドを使用して解決されたForEachメソッドのコンパイルエラー
- デフォルトの方法と多重継承のあいまいさの問題
- Javaインターフェースのデフォルトメソッドに関する重要なポイント:
Javaインターフェイスの静的メソッド
- Javaインターフェイスの静的メソッド、コード例、静的メソッドとデフォルトメソッド
- Javaインターフェースの静的メソッドに関する重要なポイント:
Java機能インターフェース
Java 8の抽象クラスとインターフェース
Java 8インターフェースの変更には、インターフェースの静的メソッドとデフォルトメソッドが含まれます。Java 8より前のバージョンでは、インターフェースにメソッド宣言しか含めることができませんでした。ただし、Java 8以降では、デフォルトのメソッドと静的メソッドをインターフェースに含めることができます。
デフォルトメソッドを導入した後、インターフェースと抽象クラスは同じように見えます。ただし、Java 8ではまだ異なる概念です。
抽象クラスはコンストラクタを定義できます。それらはより構造化されており、状態を関連付けることができます。対照的に、デフォルトのメソッドは、特定の実装の状態を参照せずに、他のインターフェースメソッドを呼び出すという観点からのみ実装できます。したがって、両方が異なる目的で使用され、2つの間の選択は、実際にはシナリオのコンテキストに依存します。
概念的な違い:
抽象クラスは、インターフェイスのスケルトン(つまり、部分的)実装に有効ですが、一致するインターフェイスがないと存在できません。
それで、抽象クラスが効果的に可視性が低くなるように削減された場合、インターフェイスのスケルトン実装では、デフォルトのメソッドもこれを取り除くことができますか?断固として:いいえ!インターフェイスを実装するには、ほとんどの場合、デフォルトのメソッドにはないクラス構築ツールの一部またはすべてが必要です。そして、いくつかのインターフェースがそうでない場合、それは明らかに特別なケースであり、あなたを迷わせるべきではありません。
Java 8のインターフェースのデフォルトメソッド
Java 8は「デフォルトメソッド」を導入します」または(Defenderメソッド)の新機能がいます。これにより、開発者は、インターフェースの既存の実装を壊すことなく、インターフェースに新しいメソッドを追加できます。これは、具象クラスがそのメソッドの実装を提供できない場合にデフォルトとして使用するインターフェース定義実装を許可する柔軟性を提供します。
それがどのように機能するかを理解するために小さな例を考えてみましょう:
public interface OldInterface {
public void existingMethod();
default public void newDefaultMethod() {
System.out.println("New default method"
+ " is added in interface");
}
}
次のクラスは、Java JDK 8で正常にコンパイルされます。
public class OldInterfaceImpl implements OldInterface {
public void existingMethod() {
// existing implementation is here…
}
}
OldInterfaceImplのインスタンスを作成する場合:
OldInterfaceImpl obj = new OldInterfaceImpl ();
// print “New default method add in interface”
obj.newDefaultMethod();
デフォルトのメソッドは決して最終的なものではなく、同期できず、オブジェクトのメソッドをオーバーライドできません。それらは常にパブリックであり、短くて再利用可能なメソッドを書く能力を厳しく制限します。
デフォルトのメソッドは、実装が含まれているため、実装クラスに影響を与えることなく、インターフェースに提供できます。実装で定義されたインターフェースに追加された各メソッドが影響を受ける場合、実装するクラスは影響を受けません。実装クラスは、インターフェースによって提供されるデフォルトの実装をオーバーライドできます。
デフォルトのメソッドを使用すると、これらのインターフェースの古い実装を壊すことなく、既存のインターフェースに新しい機能を追加できます。
デフォルトのメソッドを含むインターフェースを拡張すると、以下を実行できます。
- デフォルトのメソッドをオーバーライドせず、デフォルトのメソッドを継承します。
- サブクラスでオーバーライドする他のメソッドと同様に、デフォルトのメソッドをオーバーライドします。
- デフォルトのメソッドを抽象として再宣言し、サブクラスに強制的にオーバーライドさせます。
デフォルトのメソッドを使用して解決されたForEachメソッドのコンパイルエラー
Java 8では、JDKコレクションが拡張され、forEachメソッドがコレクション全体に追加されます(ラムダと連携して機能します)。従来の方法では、コードは以下のようになります、
public interface Iterable<T> {
public void forEach(Consumer<? super T> consumer);
}
この結果、各実装クラスはコンパイルエラーを伴うため、既存の実装が変更されないようにするために、必要な実装とともにデフォルトメソッドが追加されます。
Defaultメソッドを使用したIterableインターフェースは次のとおりです。
public interface Iterable<T> {
public default void forEach(Consumer
<? super T> consumer) {
for (T t : this) {
consumer.accept(t);
}
}
}
同じメカニズムを使用して、実装クラスを壊すことなく、JDKインターフェースにストリームを追加しました。
デフォルトの方法と多重継承のあいまいさの問題
Javaクラスは複数のインターフェースを実装でき、各インターフェースは同じメソッドシグネチャを持つデフォルトメソッドを定義できるため、継承されたメソッドは互いに競合する可能性があります。
以下の例を検討してください。
public interface InterfaceA {
default void defaultMethod(){
System.out.println("Interface A default method");
}
}
public interface InterfaceB {
default void defaultMethod(){
System.out.println("Interface B default method");
}
}
public class Impl implements InterfaceA, InterfaceB {
}
上記のコードは、次のエラーでコンパイルに失敗します。
java:クラスImplは、タイプInterfaceAおよびInterfaceBからdefaultMethod()の無関係なデフォルトを継承します
このクラスを修正するには、デフォルトのメソッド実装を提供する必要があります。
public class Impl implements InterfaceA, InterfaceB {
public void defaultMethod(){
}
}
さらに、独自の実装ではなく、スーパーインターフェースのいずれかによって提供されるデフォルトの実装を呼び出す場合は、次のようにします。
public class Impl implements InterfaceA, InterfaceB {
public void defaultMethod(){
// existing code here..
InterfaceA.super.defaultMethod();
}
}
新しいメソッドの一部として、デフォルトの実装またはその両方を選択できます。
Javaインターフェースのデフォルトメソッドに関する重要なポイント:
- Javaインターフェースのデフォルトメソッドは、実装クラスを壊すことを恐れずにインターフェースを拡張するのに役立ちます。
- Javaインターフェースのデフォルトメソッドは、インターフェースと抽象クラスの違いを埋めています。
- Java 8インターフェースのデフォルトメソッドは、すべてのコレクションクラスメソッドをインターフェース自体で提供できるなど、ユーティリティクラスを回避するのに役立ちます。
- Javaインターフェースのデフォルトメソッドは、基本実装クラスを削除するのに役立ちます。デフォルトの実装を提供し、実装クラスがオーバーライドするクラスを選択できます。
- インターフェースにデフォルトのメソッドを導入する主な理由の1つは、ラムダ式をサポートするようにJava 8のコレクションAPIを拡張することです。
- 階層内のクラスに同じシグネチャを持つメソッドがある場合、デフォルトのメソッドは無関係になります。デフォルトのメソッドは、java.lang.Objectのメソッドをオーバーライドできません。推論は非常に単純です。これは、ObjectがすべてのJavaクラスの基本クラスであるためです。したがって、インターフェイスのデフォルトメソッドとして定義されたObjectクラスメソッドがあったとしても、Objectクラスメソッドが常に使用されるため、それは役に立ちません。そのため、混乱を避けるために、Objectクラスのメソッドをオーバーライドするデフォルトのメソッドを設定することはできません。
- Javaインターフェイスのデフォルトメソッドは、Defenderメソッドまたは仮想拡張メソッドとも呼ばれます。
リソースリンク:
- Java 8のデフォルトメソッドと抽象クラスのインターフェイス
- JDK 8時代の抽象クラスとインターフェース
- 仮想拡張メソッドによるインターフェースの進化
Javaインターフェイスの静的メソッド
Javaインターフェイスの静的メソッド、コード例、静的メソッドとデフォルトメソッド
Javaインターフェースの静的メソッドは、実装クラスでオーバーライドできないことを除いて、デフォルトのメソッドに似ています。この機能は、実装クラスでの実装が不十分な場合に、望ましくない結果を回避するのに役立ちます。簡単な例でこれを見てみましょう。
public interface MyData {
default void print(String str) {
if (!isNull(str))
System.out.println("MyData Print::" + str);
}
static boolean isNull(String str) {
System.out.println("Interface Null Check");
return str == null ? true : "".equals(str) ? true : false;
}
}
次に、実装が不十分なisNull()メソッドを持つ実装クラスを見てみましょう。
public class MyDataImpl implements MyData {
public boolean isNull(String str) {
System.out.println("Impl Null Check");
return str == null ? true : false;
}
public static void main(String args[]){
MyDataImpl obj = new MyDataImpl();
obj.print("");
obj.isNull("abc");
}
}
isNull(String str)は単純なクラスメソッドであり、インターフェースメソッドをオーバーライドしないことに注意してください。たとえば、@ OverrideアノテーションをisNull()メソッドに追加すると、コンパイラエラーが発生します。
アプリケーションを実行すると、次の出力が得られます。
インターフェイスのヌルチェック
Impl Null Check
インターフェースメソッドを静的からデフォルトにすると、次の出力が得られます。
Impl Null Check
MyData印刷::
Impl Null Check
Javaインターフェースの静的メソッドは、インターフェースメソッドのみに表示されます。MyDataImplクラスからisNull()メソッドを削除すると、MyDataImplオブジェクトにそれを使用できなくなります。ただし、他の静的メソッドと同様に、クラス名を使用してインターフェース静的メソッドを使用できます。たとえば、有効なステートメントは次のようになります。
boolean result = MyData.isNull("abc");
Javaインターフェースの静的メソッドに関する重要なポイント:
- Javaインターフェースの静的メソッドはインターフェースの一部であり、実装クラスオブジェクトには使用できません。
- Javaインターフェイスの静的メソッドは、nullチェック、コレクションのソートなどのユーティリティメソッドを提供するのに適しています。
- Javaインターフェースの静的メソッドは、実装クラスによるオーバーライドを許可しないことにより、セキュリティを提供するのに役立ちます。
- Objectクラスメソッドのインターフェイス静的メソッドを定義できません。「この静的メソッドはインスタンスメソッドをObjectから隠すことができません」というコンパイラエラーが発生します。これは、Objectがすべてのクラスの基本クラスであり、1つのクラスレベルの静的メソッドと同じシグネチャを持つ別のインスタンスメソッドを持つことができないため、Javaでは許可されていないためです。
- javaインターフェイスの静的メソッドを使用して、コレクションなどのユーティリティクラスを削除し、そのすべての静的メソッドを対応するインターフェイスに移動できます。これにより、簡単に検索して使用できます。
Java機能インターフェース
投稿を締めくくる前に、機能的なインターフェースについて簡単に紹介します。抽象メソッドが1つだけのインターフェースは、機能インターフェースと呼ばれます。
@FunctionalInterface
インターフェースを機能インターフェースとしてマークするために、新しいアノテーションが導入されました。@FunctionalInterface
アノテーションは、機能インターフェースに誤って抽象メソッドが追加されるのを防ぐための機能です。オプションですが、使用することをお勧めします。
関数型インターフェースは待望され、ラムダ式を使用してそれらをインスタンス化できるため、Java 8の多くの機能が求められています。ラムダ式とメソッド参照のターゲットタイプを提供するために、一連の機能インターフェースを備えた新しいパッケージjava.util.functionが追加されました。関数型インターフェイスとラムダ式については、今後の投稿で取り上げます。
リソースの場所:
- Java 8インターフェイスの変更–静的メソッド、デフォルトメソッド