Javaのインターフェースでデフォルトメソッドを実装する
javaのインターフェースでデフォルトメソッドを実装したメモです。
デフォルトメソッド
java8からインターフェースでデフォルトメソッドが記述できるようになりました。
デフォルトメソッド実装
デフォルトメソッドの記述方法は、メソッドにdefaultキーワードをつけます。
メソッド自体は普通のメソッドと同様に記述します。
interface PrintWord { default String print(String word) { return "[" + word + "]"; } }
デフォルトメソッド使用
デフォルトメソッドを使用する場合は、インターフェースの実装クラスを作成して使用します。
PrintWord p = new PrintWord() {}; String actual = p.print("abc");
テストコード。
@Test public void デフォルトメソッド使用() throws Exception { PrintWord p = new PrintWord() {}; String actual = p.print("abc"); String expected = "[abc]"; assertThat(actual).isEqualTo(expected); }
デフォルトメソッドのオーバーライド
デフォルトメソッドを定義したインターフェースを継承して、デフォルトメソッドでオーバーライドできます。
interface MorePrintWord extends PrintWord { @Override default String print(String word) { return "[[[[[" + word + "]]]]]"; } }
使用する場合は、同様にインターフェースの実装クラスを作成して使用します。
PrintWord p = new MorePrintWord() {}; String actual = p.print("abc");
テストコード。
@Test public void デフォルトメソッドのオーバーライドの確認() throws Exception { PrintWord p = new MorePrintWord() {}; String actual = p.print("abc"); String expected = "[[[[[abc]]]]]"; assertThat(actual).isEqualTo(expected); }
デフォルトメソッドの抽象化
デフォルトメソッドを定義したインターフェースを継承して、抽象メソッドとしてオーバーライドできます。
interface AbstractPrintWord extends PrintWord { @Override String print(String word); }
使用する場合は、インターフェースを実装したクラスでメソッドを実装して使用。
PrintWord p = new AbstractPrintWord() { @Override public String print(String word) { return "[[[" + word + "]]]"; } }; String actual = p.print("abc");
テストコード。
@Test public void 再抽象化のメソッド実装() throws Exception { PrintWord p = new AbstractPrintWord() { @Override public String print(String word) { return "[[[" + word + "]]]"; } }; String actual = p.print("abc"); String expected = "[[[abc]]]"; assertThat(actual).isEqualTo(expected); }
多重継承
インターフェースは複数実装できますが、同じデフォルトメソッドを持ったインターフェースを実装する場合、
実装クラスでオーバーライドする必要があります。
Rootというインターフェースがあり、それを継承したimplAとimplBというインターフェースを用意します。
implAとimplBで同じ名前のデフォルトメソッド method()を定義します。
interface Root { String method(String str); } interface implA extends Root { @Override default String method(String str) { return "A " + str; } } interface implB extends Root { @Override default String method(String str) { return "B " + str; } }
implAとimplBを実装したImplAandBというクラスを実装します。
この場合、implAとimplBに同じメソッドがあるため、どちらを使っていいか分からないため、
コンパイルエラーになります。
// コンパイルエラー class ImplAandB implements implA, implB { }
コンパイルエラーを解消するために、インターフェースで定義されているデフォルトメソッドを
オーバーライドして実装します。
インターフェースに同じ名前のメソッドがある場合は必ずオーバーライドする必要があります。
class ImplAandB implements implA, implB { @Override public String method(String str) { return "A and B " + str; } }
テストコード。
@Test public void インターフェースの多重継承() throws Exception { ImplAandB ab = new ImplAandB(); String actual = ab.method("ab"); String expected = "A and B ab"; assertThat(actual).isEqualTo(expected); }
終わり。
ソースは一応あげときました。