インターフェース
前回では抽象クラスの解説をおこないました。
その抽象クラスのさらに特殊なものが「インターフェース」です。
インターフェースは「interface」キーワードを利用して宣言します。
以下がインターフェースの例です。
public interface Vehicle{ public void start( ); public void stop( ); }
これは「乗り物」を表すクラスですが、何の機能も実装されていません。
インターフェース内のメソッドは抽象クラスの抽象メソッドと同じです。
ただ抽象クラスは抽象メソッド以外にも、普通に実装を持つメソッドも記述できます。
インターフェースは抽象メソッドのみです。
インターフェースは抽象クラスと同じように継承して使うのですが、キーワードextendsは用いません。
「implements」というキーワードを用います。
implementsは実装という意味です。
インターフェースには機能は何もありません。
そのため継承するものはなく、サブクラスで実装しなければいけないのです。
そのため、implementsという単語を用います。
public class Car implements Vehicle{ public void start( ){ //実装を書く! } public void stop( ){ //実装を書く! } }
インターフェースのポイントは以下の通りです。
ポイント!インターフェースのメンバ
インターフェースには、定数と空メソッド(中身のないメソッド)のみ記述できます。
ポイント!インスタンスを生成することができない
抽象クラスと同じ考え方に基づいているからです。
ポイント!複数実装することができる
Javaでは多重継承が認められていません。
しかし、インターフェースを実装するのは複数できます。
これはなぜかと言うと、インターフェースAとBに同じ名前のfoo( ) メソッドがあったとしてもそれは名前だけだからです。
両方とも実装を持ちません。
実装はサブクラスにしかないので、同じ名前が重なっても困ることがないからです。
【インターフェースの利用】
Vehicleインターフェース
public interface Vehicle{ public void start( ); public void stop( ); }
Taxiクラス
public class Taxi implements Vehicle{ public void start( ){ System.out.println("タクシーが出発します"); System.out.println("お客さんを乗せました"); } public void stop( ){ System.out.println("タクシーが止まりました"); System.out.println("料金を精算します"); } }
Truckクラス
public class Truck implements Vehicle{ public void start( ){ System.out.println("トラックが出発します"); System.out.println("目的地を目指します"); } public void stop( ){ System.out.println("トラックが止まりました"); System.out.println("積荷を降ろします"); } }
UseVehicleクラス
public class UseVehicle{ public static void main(String[ ] args){ Vehicle v[ ] = new Vehicle[3]; v[0] = new Taxi( ); v[1] = new Truck( ); v[2] = new Taxi( ); for(int i = 0; i < 3; i++){ v[i].start( ); } for(int i = 0; i < 3; i++){ v[i].stop( ); } } }
実行結果
タクシーが出発します お客さんを乗せました トラックが出発します 目的地を目指します タクシーが出発します お客さんを乗せました タクシーが止まりました 料金を精算します トラックが止まりました 積荷を降ろします タクシーが止まりました 料金を精算します
インターフェースの基本的な使い方は抽象クラスと同じように、汎化をすることです。
インターフェースVehicleには、乗り物に必要な機能start( )とstop( )が宣言されています。
これを実装するクラスTaxiとTruckではすべてのメソッドを実装する必要があります。
出発と到着の機能がない乗り物では意味がないので、実装しなければいけないのです。
このように、「すべての乗り物は出発と到着の機能が必要である」という設計を与えています。
もし、一部の機能を実装しないとコンパイルエラーになります。
【定数とインターフェース】
インターフェースには他の活用方法もあります。
インターフェースには定数も記述できるので、定数だけを記述したインターフェースを作るという方法です。
public interface Constants{ public static final double PI = 3.14; }
public class UseConstants implements Constants{ public static void main(String[ ] args){ int radius = 10; double S = radius * radius * PI; System.out.println("半径" + radius + "の円の面積は" + S + "です"); } }
実行結果
半径10の円の面積は3.14です
Javaで定数を定義したい場合は通常public static finalとします。
このインターフェースを実装したクラスでは、ただPIと書くだけで定義した値を使用できます。
もちろん、他のクラスでも同様にConstantsインターフェースを利用できます。
ここで、円周率の精度を上げたい場合は、3.14を3.1416などと変更します。
すると、このインターフェースを使用しているクラスではすべて新しいPIの値を使用します。
このように定数を一元管理できるというメリットもあります。
インターフェースの継承
あるインターフェースをもとに、それを継承したサブインターフェースを作成することができます。
継承関係ですので、extendsキーワードを使用します。
サブインターフェースを実装したクラスが具象クラスの場合は、スーパーインターフェース、サブインターフェースのすべてのメソッドをオーバーライドする必要があります。
例えば、Vehicle(乗り物)というインターフェースがあり、start()メソッドとstop()メソッドが定義されているとします。
このインターフェースでは、2つのメソッドは中身のない名前だけのメソッドです。
次にVehicle(乗り物)よりも具体的なPassengerVehicle(お客さんを乗せる乗り物)のインターフェースを作ります。
ここにはcalcFare()メソッドという料金を精算するメソッドを定義します。
PassengerVehicleインターフェースでは、Vehicleインターフェースに定義されたstart()メソッドとstop()メソッドも利用したいので、Vehicleをスーパーインターフェース、PassengerVehicleをサブインターフェースにして継承関係(extends)を作ります。
TaxiクラスとBusクラスはお客さんを乗せるので、PassengerVehicleインターフェースを実装(implements)します。
TaxiクラスとBusクラスはVehicleインターフェースとPassengereVehicleインターフェースを実装しているので、start()メソッドとstop()メソッド、calcFare()メソッドをすべて、動作を具体的に記述してオーバーライドしなければなりません。
一方、Truckクラスは、お客さんは乗せず、乗り物としての機能だけがほしいのでVehicleインターフェースを実装(implements)し、start()メソッドとstop()メソッドをオーバーライドします。
【インターフェースの継承】
前述のVehicleインターフェースを継承したPassengerVehicleインターフェース
public interface PassengerVehicle extends Vehicle { public void calcFare(); }
前述のTaxiクラスを変更
public class Taxi implements PassengerVehicle{ public void start(){ System.out.println("タクシーが出発します"); } public void stop(){ System.out.println("タクシーが止まりました"); } public void calcFare(){ System.out.println("タクシー料金を精算します"); } }
Busクラス
public class Bus implements PassengerVehicle { public void start(){ System.out.println("バスが停留所から発車します"); } public void stop(){ System.out.println("バスが停留所に止まりました"); } public void calcFare(){ System.out.println("バス料金を精算しました"); } }
前述のTruckクラスを変更
public class Truck implements Vehicle { public void start(){ System.out.println("トラックが出発します"); } public void stop(){ System.out.println("トラックが止まりました"); } }
前述のUseVehicleクラスを変更
public class UseVehicle { public static void main(String[] args) { PassengerVehicle v[] = new PassengerVehicle[2]; v[0] = new Taxi(); v[1] = new Bus(); for(int i = 0; i < 2 ; i++){ v[i].start(); } for(int i = 0; i < 2 ; i++){ v[i].calcFare(); } for(int i = 0; i < 2 ; i++){ v[i].stop(); } Truck t = new Truck(); t.start(); t.stop(); } }
実行結果
タクシーが出発します バスが停留所から発車します タクシー料金を精算します バス料金を精算しました タクシーが止まりました バスが停留所に止まりました トラックが出発します トラックが止まりました
クラス間のイメージはこのようになります。
それぞれのクラスにメソッドがそろっているかどうか確認しましょう。
まとめ
インターフェース
- インターフェースは特殊な抽象クラスです。
- インターフェースは定数と空メソッドのみを持ちます。
- インターフェースはインスタンス化できません。
- インターフェースは複数実装(継承)できます。
独学で挫折しそうになったら、オンラインプログラミングスクール