1. デフォルトインターフェースメソッド導入の背景
Java8は、度重なるJavaのバージョンアップの過程で最も変化したバージョンと言える(生き残るためには時代に遅れずについていくべきだろう)が、その後は長年の開発と反復により、Java のソース コードはすでに巨大になっており、このような膨大な量の作業を行うのは決して簡単ではありません。そのため、Java 8 のデフォルトのインターフェイス メソッドを初めて見たとき、最初に感じたのは、これは Java 設計者が埋める前に掘った穴ではないかということでした。
これまでの説明から、Java8 では List の sort(Comparator super E> c) メソッドなど、既存のインターフェイスに多くのメソッドが追加されていることがわかりました。 Java 8 より前のインターフェースの設計思想に従っている場合、インターフェースにメソッド宣言を追加するとき、インターフェースを実装するクラスは、新しく追加されたメソッドに対応する実装を追加する必要があります。互換性を考慮すると、これはお勧めできません。したがって、これは落とし穴であり、新しい機能では、両方の長所を活かすために、インターフェイスにいくつかの新しいメソッドを追加する必要があります。Java8 の設計者は、デフォルトのインターフェイス メソッドという概念を提案しました。
このように、デフォルトのインターフェースメソッドは、私たち一般の開発者からはまだ遠いところにある API 設計者向けに開発されているようです。JDK を設計する必要はありませんが、このように考えるのは少し簡単です。日々の開発プロセス 他のビジネス パーティが呼び出すための API を提供する必要は依然としてありますが、API を更新する場合、互換性を維持しながら、デフォルトのメソッドを使用して、より高度な機能を提供できます。
2. デフォルトのインターフェースメソッドの定義
デフォルトのインターフェースメソッドの定義は非常に簡単で、次のようにインターフェースのメソッド定義の前にdefault キーワードを追加するだけです。このインターフェースのサブクラスはすべて、このメソッドを間接的に保持します。あるいは、私と同じように、インターフェイスと抽象クラスはますます似てきていると感じるかもしれませんが、確かに、それらの間には次のような違いがあります:
上で述べた問題を解決することに加えて、抽象化には次の利点もあります:
1. すべてのサブクラスで必要とされない一部のメソッドについては、デフォルトを与えます。
2. デフォルトのメソッドは、Java での多重継承のための新しい方法を提供します (継承できるクラスは 1 つだけですが、複数のインターフェイスを実装できます)。 、そしてインターフェースもデフォルトメソッドを定義できるようになりました)
クラスは複数のインターフェースを実装できるため、クラスが複数のインターフェースを実装すると、2 つ以上のインターフェースがある場合に競合が発生します。これらのインターフェースで同じメソッド署名を持つデフォルトメソッドは、競合を解決するために次の 3 つの原則を定義しています:
1. クラスまたは親クラスで明示的に宣言されたメソッドの優先順位は、すべてのデフォルトメソッドよりも高くなります
2ルール 1 が失敗した場合は、現在のクラスに最も近い特定の実装を持つデフォルトのメソッドを選択します
例 1
public interface A { /** * 默认方法定义 */ default void method() { System.out.println("This is a default method!"); } }
ここで、インターフェイス B は A よりも C に近く、ルール 2 に従って B のメソッドは特定のデフォルト実装であるため、実際に呼び出されるのはインターフェイス B のデフォルトのメソッドです
例 2
public interface A { /** * 默认方法定义 */ default void method() { System.out.println("A's default method!"); } }public interface B extends A { /** * 默认方法定义 */ default void method() { System.out.println("B's default method!"); } }public class C implements A, B { public static void main(String[] args) { new C().method(); } }// 输出:B's default method!
例 2 では、元のインターフェイス A と B に基づいてインターフェイス A を実装するクラス D を追加します。次に、クラス C が D を継承し、A と B を実装します。ここでは C が D に近いですが、D の具体的な実装は次のとおりです。 A、B のデフォルト メソッドは、ルール 2 に従って、実際にはここで呼び出されます。
例 3
// A接口不变public interface B { /** * 默认方法定义 */ default void method() { System.out.println("B's default method!"); } }public class C implements A, B { @Override public void method() { // 必须显式指定 B.super.method(); } public static void main(String[] args) { new C().method(); } }
例3中接口B不再继承自接口A,所以此时C中调用默认方法method()距离接口A和B的具体实现距离相同,编译器无法确定,所以报错,此时需要显式指定:B.super.method()。