特集PC技術

Java言語入門 ~C言語を学んだ君へ~

 

[第10回] インタフェース

今まで継承をメインに進めてきましたが、継承だけではどうしても駄目な点がありました。
そう、多重継承(class A extends B, C等)ができない点です。
その多重継承を解決するために用意されているものが、これから説明するインタフェースなのです。
この継承に似ているインタフェースがどういうもので、どのような機能があるか、どんな時に使うのかを覚えてください。

目次

[1] インタフェースの基本

まずは、インタフェースがどういうものなのか説明します。

インタフェースとは、「定数」と「抽象メソッド」をひとまとめにしたもの

定数とは文字通り、変更不可の値のことです。第9回で説明しました、final(第9回参照)のことです。
抽象メソッドとは、オーバーライドを前提に定義したメソッドです。abstract(第9回参照)のことです。
では、このインタフェースをどのように使用するかを説明します。
まずは、次のクラス図を見てください。これは、誤った例です。
誤ったクラス図
「人間」から「警察官」を、「犬」から「警察犬」を継承しています。
一見良さそうですが、このような継承の仕方は誤りです。理由は、

継承とは「系統」を表す

ものだからです。上の図では哺乳類の種類を系統化したものであり、
「警察官」や「警察犬」は哺乳類の継承に当てはまらないからです。
生まれた時から「警察官」の人はいません。

では、どうすればよいでしょうか。ここで登場するのが、インタフェースです。
継承は「系統」に使用しますが、インタフェースは「機能」として使用します。
つまり、人間と犬に「警察」という「機能」を付ければよいのです。
誤ったクラス図
これで、正しい「警察官」と「警察犬」ができました。
もし、「医者」になりたければ医者のインタフェースを付けるだけです。
プログラムの世界は簡単に職業が選べます。
インタフェースの説明は以上です。
継承とインタフェースの違いはわかりにくいと思いますが、
以降で少しずつインタフェースの理解を深めてください。

インタフェースの基本形

インタフェースを定義するには、interfaceというキーワードを使います。
次のように記述します。

interface Name{
	int VALUE = 10; // 定数
	void method(); // 抽象メソッド
} 

Nameにはインタフェース名を書きます。
そして、「定数」と「抽象メソッド」はいくつ記述してもかまいません。
また、不思議に思ったでしょうが「final」を使わなくても、「int VALUE = 10;」で定数になります。
さらに「abstract」を付けなくても「void method();」で抽象メソッドになります。

インタフェースには「定数」と「抽象メソッド」のキーワードを意識する必要はない

この部分はとても大切なので覚えましょう。
そして、「抽象メソッド」は「機能」として使われるため、外部公開が必要になります。
したがって、上記の定義方法は以下の定義方法と全く同じ意味になります。

interface Name{
	public static final int VALUE = 10; // 定数
	public abstract void method(); // 抽象メソッド
}

「定数」には「public static final」を、「定義」には「public abstract」を付けることがあらかじめ決まっています。
そのため、あえて書く必要はなく、省略ができます。

[2] インタフェースの実装

インタフェース内で定義した「抽象メソッド」に「中身を書く」ことを実装と言います。
では、実際に実装します。次のソースを見てください。

サンプルプログラム
// インタフェースA
interface InterA {
	int VALUE_A = 10;
	void methodA();
}
// インタフェースB
interface InterB {
	int VALUE_B = 20;
	void methodB();
}
// インタフェースを実装するクラス
class AB implements InterA, InterB {
	// 実装
	public void methodA() {
		System.out.println("methodAの実装");
	}

	// 実装
	public void methodB() {
		System.out.println("methodBの実装");
	}
}
public class Java10_01 {
	public static void main(String args[]) {
		// クラスABの定数を表示
		System.out.println(AB.VALUE_A);
		System.out.println(AB.VALUE_B);

		AB ab = new AB();
		// クラスABのメソッドの呼び出し
		ab.methodA();
		ab.methodB();
	}
}
実行結果

実行結果

今回はインタフェースを2つ定義しました。インタフェースAとインタフェースBです。
そして、クラスABでインタフェースを実装してします。

インタフェースを実装するときはimplementsキーワード

クラスの時は「extends」を使いましたが、インタフェースの場合には「implements」を使います。
このとき、実装するインタフェースはいくつでもかまいません。
継承と違って複数実装することができるわけです。複数の場合は「,」で区切ります。
その後、指定したインタフェースにある抽象メソッドを実装、つまり「オーバーライド」します。
実装しなければ、コンパイルエラーが起こります。
クラスJava10_01では、クラスABにある定数と、メソッドを呼び出しています。
実行結果より、クラスABで定義しなかった定数も使用できることが確認できます。

[3] インタフェースの継承

インタフェースにも継承があります。継承をするには「extends」を使います。
これはクラスの継承と同じです。しかし、クラスと違って、インタフェースでは「多重継承」ができます。
次のソースを見てください。

サンプルプログラム
// インタフェースA
interface InterA {
	int VALUE_A = 10;
	void methodA();
}
// インタフェースB
interface InterB {
	int VALUE_B = 20;
	void methodB();
}
// インタフェースC(2つのインタフェースを継承)
interface InterC extends InterA, InterB {
	int VALUE_C = 30;
	void methodC();
}

// インタフェースを実装するクラス
class AB implements InterC {
	// 実装
	public void methodA() {
		System.out.println("methodAの実装");
	}
	// 実装
	public void methodB() {
		System.out.println("methodBの実装");
	}
	// 実装
	public void methodC() {
		System.out.println("methodCの実装");
	}
}
public class Java10_02 {
	public static void main(String args[]) {
		// クラスABの定数を表示
		System.out.println(AB.VALUE_A);
		System.out.println(AB.VALUE_B);
		System.out.println(AB.VALUE_C);

		AB ab = new AB();
		// クラスABのメソッドの呼び出し
		ab.methodA();
		ab.methodB();
		ab.methodC();
	}
}
実行結果

実行結果

インタフェースInterCがInterAとInterBを「多重継承」しています。
この場合、継承するごとに「,」で区切ります。
「継承」によって、インタフェースInterCは、3つのインタフェースの機能を持つことになります。
そのため、クラスABはインタフェースInterCのみを指定するだけで、
3つのインタフェースの機能を使えるようになります。

Javaはクラスの「多重継承」をサポートしていません。
その理由は複数のクラスの変数やメソッドを継承すると、機能が複雑になってしまうからです。
しかし、インタフェースは「定数」と「抽象メソッド」しか定義していません。
そのため、いくつ継承しても複雑にならず「多重継承」ができます。

インタフェースのアクセス修飾子

インタフェースにもアクセス修飾を付けることができます。次のように書きます。
public interface InterA { : }

[4] インタフェースの参照

前ページでインタフェースの基本的なことは分かったと思います。
では、インタフェースによるさまざまな使い方を説明します。

インタフェースの参照とは

インタフェースはクラスと異なり、インスタンス化はできません。
しかし、インタフェースを実装したオブジェクトをインタフェースの型が参照することはできます。

サンプルプログラム
interface Inter {
	void method();
}
class L implements Inter {
	public void method() {
		System.out.println("Lのメソッド");
	}
}

public class Java10_03 {
	public static void main(String args[]) {
		Inter inter;	// インタフェースInter型を宣言
		inter = new L();	// インタフェースInterがクラスLを参照
		inter.method();
	}
}
実行結果

実行結果
クラスJava10_03で、インタフェースinterがクラスLのオブジェクトを参照しています。
インタフェースの変数はこのような書き方ができます。
用途としては、「ポリモーフィズム」が実現できます。
これについては、次の項目で説明します。

[5] インタフェースとポリモフィーズム

ここでは、インタフェースを使ったポリモーフィズムの実現方法を説明します。
前項目でインタフェースの参照について説明しました。
そもそも、この参照とはポリモーフィズムを実現するための機能です。
では、どのように実現するのか、次のソースを見てください。

サンプルプログラム
// 職業:警察
interface Police {
	void investigate();	// 捜査する
}
// 警察官
class Policeman implements Police {
	public void investigate() {
		System.out.println("人間は聞き込みをする");
	}
}
// 警察犬
class PoliceDog implements Police {
	public void investigate() {
		System.out.println("犬はにおいを辿る");
	}
}
public class Java10_04 {
	public static void main(String args[]) {
		Police police[] = new Police[2];	// 配列生成
		police[0] = new Policeman();	// 警察官生成
		police[1] = new PoliceDog();	// 警察犬生成

		for (int i = 0; i < police.length; i++) {
			police[i].investigate();	// 捜査命令!
		}
	}
}
実行結果

実行結果

ソース中に、インタフェースの参照が使われています。
実行結果より、ポリモーフィズムが確認できたと思います。
ポリモーフィズムについてはすでに第9回の継承で説明したので、特に説明することはありません。
注意点として、クラスJava10_04でインタフェースの配列を宣言しました。
これは、インタフェースをインスタンス化したのではなく、インタフェースの領域を確保したということです。
くれぐれも間違えないようにしてください。

[6] instanceof

インタフェースの参照について説明しました。
これは、インタフェース型の変数がオブジェクトを参照するというものです。
ところがこの参照をしている状態では、オブジェクト本来の型が何であったかわかりません。
そこで、使用するものが、instanceofです。これは次のように使います。

instanceofの形式

対象 instanceof 型名

「対象」には、調べたいオブジェクトを、「型名」には、対象と比較する型を入れます。
もし、「対象」が「型名」と一致した場合、「true」を返します。そうでなければ「false」を返します。
では、実際に使ってみます。次のソースを見てください。

サンプルプログラム
interface LAN {
}

class PC implements LAN {
}

class Printer implements LAN {
}

public class Java10_05 {
	public static void main(String args[]) {
		LAN lan[] = new LAN[2];
		lan[0] = new PC();
		lan[1] = new Printer();

		for (int i = 0; i < lan.length; i++) {
			if (lan[i] instanceof PC) {
				System.out.println("パソコンです");
			} else {
				System.out.println("パソコンではありません");
			}
		}
	}
}
実行結果

実行結果
instanceofによって、配列に格納したオブジェクトが、クラスPCであるか、そうでないかを判定しています。
実行結果より、正しく判定できたことが確認できます。

[7] 抽象クラスとインタフェース

これまでに「ポリモーフィズム」を実現する方法をいくつか説明しました。
そして、実現のために使用したものに「抽象クラス」と「インタフェース」がありました。
どちらを使っても実現はできます。
そのため、この2つの違いがわかりにくかったかもしれません。
ここでは、この2つの使い分けをどのようにすればよいかを簡単に説明します。
まず、2つの特徴をそれぞれ説明します。
「抽象クラス」は「抽象メソッド」を含め、通常のメソッドや、変数なども定義できます。
しかし、クラスであるために、「系統」の異なるクラスへは適用できません。
それに対し、「インタフェース」はクラスの「系統」を気にせず、どのクラスにも適応できます。
しかし、「定数」と「抽象メソッド」しか定義できません。
つまり、簡単に説明すると、系統に従えるなら、「抽象クラス」を使います。
そうでなければ、「インタフェース」を使えばよいということです。
やはり、まだわかりにくいと思います。 Javaを使ってどんどんソースを書いていくと、違いがわかってくると思います。

[8]練習問題 第1問

以下の指示に従ってプログラムを作成しなさい。
なお、ファイル名はEx10_01.javaとする。

作成にあたっての条件

以下の条件を満たす、Nインタフェースを作成しなさい。

定数 :int型定数N(値は10とする)
抽象メソッド :bメソッド

上記のインタフェースが作成できたら、このインタフェースを実装したクラスEx10_01を作成しなさい。
*なお、メソッドの処理内容は自由に書いてよい。

[9]第1問解答

[10]練習問題 第2問

以下のプログラムの実行結果を答えなさい。
問題プログラム

[11]第2問解答

[12]練習問題 第3問

以下の設問について〇か×で答えなさい。

1.インタフェースは変数と抽象メソッドを定義したものである
2.インタフェースは多重継承ができる
3.インタフェースはポリモーフィズムを実現する機能を持つ

[13]第3問解答

コメント

*ςλιησηⅡ*

初めまして、*ςλιησηⅡ*と申します

[5] インタフェースとポリモフィーズム

とありますが、この部分以外のところは全て「ポリモーフィズム」となっているので、「ポリモフィーズム」ではなく、「ポリモーフィズム」へ統一したほうがいいのではないでしょうか

2016年8月 4日 23:25

コメントの投稿


画像の中に見える文字を入力してください。

トラックバックURL

http://www.isl.ne.jp/cgi-bin/mt/mt-tb.cgi/1079

pagetopこのページの先頭へ戻る