interfaceはメソッドの処理内容を具体的に書かず、型だけを宣言します。
後でメソッドを宣言できて、変更がしやすいなどのメリットはあります。
しかし、継承クラスを実装しオーバーライドであらためてメソッドを宣言するなど、記述量が増えたり、コードが読みづらくなったりとちょっと面倒もありますよね。
そんな場合は、Java8から言語拡張されたdefaultメソッドを使うと便利です。
これを使うと、実装するクラス内でメソッドの処理内容をあらためて記述する必要がなくなります。
この記事では、そんなinterfaceのdefaultについて以下の内容で解説していきます。
・interfaceのdefaultとは
・defaultの使い方
・多重継承でdefaultメソッドの名称が同じ場合の対処方法
・インターフェースでstaticメソッドを使う方法
などの基本から応用的な内容についても解説していきます。
今回は、interfaceのdefaultについて、使い方をわかりやすく解説します!
なお、Javaの記事については、こちらにまとめています。
interfaceのdefaultとは
Java8でインパクトのある言語拡張の一つが、interfaceのdefaultメソッドです。
interfaceでは処理内容を具体的に書かかず、メソッドの型だけを宣言していましたが、defaultメソッドにより処理内容を実装したメソッドを定義できるようになりました。
これによって、実装するクラス内でオーバーライドしてメソッドの処理内容を記述する必要がなくなります。
defaultの使い方
実際にdefaultの使い方を見ていきましょう。
基本的な使い方
わかりやすい例からみていきましょう。
interface内のメソッドの型の宣言の前に「default」句を記述します。
interface InterfaceJpn{ //default句を使うことで、interface内にメソッドを実装 default String greeting(){ return "Hello Japan!"; } } class ClassJpn implements InterfaceJpn{ //オーバーライドしない } public class Main { public static void main(String[] args) { ClassJpn cj = new ClassJpn(); System.out.println(cj.greeting()); } }
実行結果:
Hello Japan!
上記例では、InterfaceJpnインターフェースのgreetingメソッドに処理を定義しています。
InterfaceJpnインターフェースを実装するClassJpnクラスではgreetingメソッドをオーバーライドしていませんが、コンパイルエラーにはなりません。
これがJava8からの大きな変更点です。
Mainクラスでは、ClassJpnクラスのインスタンスを生成し、greetingメソッドの実装が呼び出されています。
多重継承でメソッド名が同じ場合(暗黙的なメソッドの指定)
ここで、ちょっと気になることが出てきませんか?
インターフェースと言えば多重継承が可能です。
defaultメソッドで実装が可能になったということは、多重継承の場合、defaultメソッドで宣言したメソッドの名称が同じで処理内容が違うという場合は、どうなってしまうのでしょうか?
例を挙げてみていきます。
interface InterfaceJpn{ default String greeting(){ return "Hello Japan!"; } } interface InterfaceTky extends InterfaceJpn{ default String greeting(){ return "Hello Tokyo!"; } } interface InterfacePref extends InterfaceJpn{ //オーバーライドしない } class ClassPref implements InterfaceTky, InterfacePref{ } public class Main { public static void main(String[] args) { ClassPref cp = new ClassPref(); System.out.println(cp.greeting()); } }
実行結果:
Hello Tokyo!
メソッドの名称が同じで重複が生じた場合、どちらのメソッドが呼び出されるかは、優先順位が付けられて選ばれています。
上記例の場合は、InterfaceJpnインターフェースとInterfaceTkyインターフェースとでgreetingメソッドが重複しています。
優先順位の付け方として、メソッドを呼び出しているクラスから最も近い位置にあるメソッドが選ばれるということになっています。
上記例の場合はInterfaceTkyインターフェースのメソッドが呼ばれ、”Hello Tokyo!”と結果表示されることになります。
多重継承でメソッド名が同じ場合(明示的なメソッドの指定)
先ほどの例では、InterfacePrefインターフェースでメソッドをオーバーライドしませんでしたが、もしInterfacePrefインターフェースでもメソッドをオーバーライドして処理を定義した場合、InterfaceTkyとInterfaceOskとで優先順位は付けにくいですよね。
これも例をみていきましょう。
interface InterfaceJpn{ default String greeting(){ return "Hello Japan!"; } } interface InterfaceTky extends InterfaceJpn{ default String greeting(){ return "Hello Tokyo!"; } } interface InterfaceOsk extends InterfaceJpn{ default String greeting(){ return "Hello Osaka!"; } } class ClassPref implements InterfaceTky, InterfaceOsk{ @Override public String greeting() { // super句を使って呼びたい方を選ぶ return InterfaceOsk.super.greeting(); } } public class Main { public static void main(String[] args) { ClassPref cp = new ClassPref(); System.out.println(cp.greeting()); } }
実行結果:
Hello Osaka!
ClassPrefクラスでオーバーライドする際に、「super」句を使って呼びたい方を選びます。
上記例の場合は、InterfaceOskインターフェースのメソッドの方を呼んでいますので、”Hello Osaka!”と結果表示されます。
インターフェースでstaticメソッドを使う方法
その他のJava8の変更点として、staticメソッドが定義できるようにもなりました。
インターフェース内にメソッドの処理内容を実装する点で、defautメソッドと似ています。
staticメソッドが使えるメリットはInterfaceから実行できて、「implement」句を使って継承クラスを実装する必要がないことです。
それでは、例を使ってみていきましょう。
interface InterfaceJpn{ //static句を使うことで、interface内にメソッドを実装 public static String greeting(){ return "Hello Japan!"; } } public class Main { public static void main(String[] args) { //staticメソッドでインスタンスを生成せずにInterfaceから実行 System.out.println(InterfaceJpn.greeting()); } }
実行結果:
Hello Japan!
InterfaceJpnインターフェースでは、「static」句を使ってgreetingメソッドを実装しています。
staticメソッドを使っているので、MainクラスではInterfaceJpnインターフェースからインスタンスを生成せずに実行しています。
インスタンスが必要ないので、実装クラスも必要ありません。
インターフェースを実装するクラスとメソッド、そしてそのクラスをインスタンス化する記述が必要ないので、コードがかなりスッキリしますね!
interface(インタフェース)の使い方総まとめ
interface(インタフェース)のいろいろな使い方を次の記事にまとめているので、ぜひ確認してください!
まとめ
ここでは、Java8から言語拡張されたインタフェースのdefaultメソッドの使い方やstaticメソッドの使い方について説明しました。
defaultメソッドやstaticメソッドを使うことでインターフェース内にメソッドを実装することができます。
そうすることで、defaultメソッドにより実装クラスでのオーバーライドの必要がなくなったり、staticメソッドにより実装クラスの記述やインスタンス化の記述も必要ありません。
記述量が減らせるメリットを感じて頂けましたでしょうか?
Java8からの拡張ですので、比較的新しい記述方法になります。
なので慣れが必要かもしれませんが、そんな場合はこの記事を何度も参考にして下さいね!