最後に紹介するのは「インタフェース」です。
このインタフェース、Javaの中で最も「なんのためにあるの?」と思われている機能です。
でもこのインタフェースが分かればオブジェクト指向に一気に近づきます!
ラストスパート、がんばりましょう!
インタフェースを使ってみる
前章で「抽象クラス」を紹介しました。
これを強力にした「インタフェース」というものを今回使ってみましょう。
/**
* インタフェース。
*/
interface PrintInterface
{
/**
* 抽象メソッド。
*/
void printMyName();
}
/**
* PrintInterfaceインタフェースの実装クラス。
*/
class Implemented implements PrintInterface
{
/**
* 抽象メソッドをオーバーライドします。
*/
public void printMyName()
{
System.out.println( "Implemented" );
}
}
/**
* 実行用クラス。このクラスを実行してください。
*/
class ImplementedRunner
{
public static void main( String[] args )
{
// Implementedクラスのインスタンスを1つ作ります。
// 参照型変数はPrintInterfaceクラスです。
PrintInterface ref = new Implemented();
// 実装したメソッドを呼び出します。
ref.printMyName();
// 実行結果:
// Implemented
}
}
// ImplementedRunner.java /** * インタフェース。 */ interface PrintInterface { /** * 抽象メソッド。 */ void printMyName(); } /** * PrintInterfaceインタフェースの実装クラス。 */ class Implemented implements PrintInterface { /** * 抽象メソッドをオーバーライドします。 */ public void printMyName() { System.out.println( "Implemented" ); } } /** * 実行用クラス。このクラスを実行してください。 */ class ImplementedRunner { public static void main( String[] args ) { // Implementedクラスのインスタンスを1つ作ります。 // 参照型変数はPrintInterfaceクラスです。 PrintInterface ref = new Implemented(); // 実装したメソッドを呼び出します。 ref.printMyName(); // 実行結果: // Implemented } }
まず最初に出てくるPrintInterfaceが「インタフェース」というものです。
* インタフェース。
*/
interface PrintInterface
{
/**
* 抽象メソッド。
*/
void printMyName();
}
/** * インタフェース。 */ interface PrintInterface { /** * 抽象メソッド。 */ void printMyName(); }
インタフェースはクラスに似ていますが、ちょっと違います。
まず「class」ではなく「interface」を付けます。「interface 名前 { ~ }」とすることで、インタフェースを作ることができます。
中カッコの中身には、普通のメソッドは書くことができません。
この例のように、抽象メソッドは書くことができます。その際、抽象クラスと違って「abstract」を付ける必要はありません。普通にメソッドを書き、「{~}」の代わりに「;」を書けばそれが抽象メソッドになります。
また、インタフェースはフィールドを持つことができません。インタフェースの中に書けるのは「抽象メソッド」と「public static finalなフィールド」のみです。
まぁインタフェースには抽象メソッドしか書けないと憶えましょう。
インタフェースは抽象クラスのようなものなので、使う時にはサブクラスのようなものを作る必要があります。
この例ではImplementedクラスがそれに当たります。
* PrintInterfaceインタフェースの実装クラス。
*/
class Implemented implements PrintInterface
{
/**
* 抽象メソッドをオーバーライドします。
*/
public void printMyName()
{
System.out.println( "Implemented" );
}
}
/** * PrintInterfaceインタフェースの実装クラス。 */ class Implemented implements PrintInterface { /** * 抽象メソッドをオーバーライドします。 */ public void printMyName() { System.out.println( "Implemented" ); } }
こちらは普通のクラスです。ただ、やっぱりちょっとだけ違います。
まず、「extends」の代わりに「implements」を使います。これまで継承は「class A extends B」としていましたが、インタフェースからの場合は「class A implements B」と書きます。
また、用語もちょっと違います。「class A extends B」のAは「スーパークラス」、Bは「サブクラス」でした。ところがインタフェースの場合、「class A implements B」のAは「実装クラス」、Bは「インタフェース」と呼びます。
つまり、Implementedクラスは実装クラスです。PrintInterfaceインタフェースから見て、Implementedクラスは実装クラスなのです。
へんてこな用語が出てきて戸惑うかもしれませんが、この用語は大事なので憶えてください。
オーバーライドの仕方は抽象クラスの時の同じです。抽象メソッドと同じ名前のメソッドを作ればOKです。
ただ、また用語が違います。インタフェースの抽象メソッドは、「サブクラスでオーバーライドする」ではなく「実装クラスで実装する」と言います。「オーバーライド」じゃなく「実装」、です。
あと、インタフェースの抽象メソッドは自動的にpublicなメソッドになるので、実装したメソッドにはpublicを付ける必要がありますのでこの点も注意しておいてください。
今紹介したPrintInterfaceインタフェースとImplementedクラスは、「9.1 abstractクラスとabstractメソッド」のAbstractSuperクラスとConcreteSubクラスの関係と同じです。
インタフェースは、機能的には抽象クラスの強化版、抽象メソッドしか書けず普通のフィールドやメソッドは持てないクラス、と考えると分かりやすいでしょう。
使う時は抽象クラスの時と同じです。
// 参照型変数はPrintInterfaceクラスです。
PrintInterface ref = new Implemented();
// Implementedクラスのインスタンスを1つ作ります。 // 参照型変数はPrintInterfaceクラスです。 PrintInterface ref = new Implemented();
Implementedクラスのインスタンスを作り、その参照をPrintInterfaceインタフェースの参照型変数で受け取ります。
そして、インタフェースの抽象メソッドを通して、実装クラスで実装しているメソッドを呼び出すことができます。
ref.printMyName();
// 実行結果:
// Implemented
// 実装したメソッドを呼び出します。 ref.printMyName(); // 実行結果: // Implemented
抽象メソッドのprintMyName()メソッドを呼び出すと、そのメソッドを実装している「ImplementedクラスのprintMyName()メソッド」が呼び出されます。
このあたりの使用感は抽象メソッドと同じですし、ポリモーフィズムが行われていると素直に考えるといいでしょう。
このように、インタフェースは抽象クラスに非常によく似ています。
特に機能的には「抽象クラスの強化版」と考えて問題ありません。
でも実は全然別物だったりします。その違いをこれからゆっくり見ていきましょう。