インターフェイスを作る

みるくあいらんどっ! > ドキュメント > Java > じっくり学ぶ Java講座 [初心者向け・入門]


インターフェイスの作成方法

予約語interfaceを使用して独自のインターフェイスを作成します。1個のフィールドと 1個のメソッドを宣言したインターフェイスの作成方法は、例えば以下のようになります。

public interface Sample {
	public static final int FIELD = 1;
	
	public abstract void method();
}

なお、フィールドについては自動的にpublic static finalが、メソッドについては自動的にpublic abstractが補完されます。したがって、以下のように記述しても同じです。本ウェブサイトでは省略をせずに記述することとします。

public interface Sample {
	int FIELD = 1;
	
	void method();
}

なお、インターフェイスはクラスではないのでextends Object」は補完されません。上記のサンプルコードには extendsが使用されていないため、親となるインターフェイスは存在しない、ということになります。以下のような記述はビルドエラーになります。

public interface Sample extends Object { // ビルドエラー
	public static final int FIELD = 1;
	
	public abstract void method();
}

インターフェイスを作成する

インターフェイス Movableと、それを実装する Carクラスを作成し、その動作検証を行っています。

ソースコードは以下の通り。

P201/Movable.java

/**
 * 移動可能なことを表すインターフェイスです。
 */
public interface Movable {
	
	/**
	 * 前進します。
	 */
	public abstract void move();
	/**
	 * 後退します。
	 */
	public abstract void back();
}

P201/Car.java

/**
 * 車を表すクラスです。
 */
public class Car implements Movable {
	/**
	 * 名前。
	 */
	private String name;
	
	/**
	 * コンストラクタ。
	 */
	public Car() {
		this("名無しの車");
	}
	
	/**
	 * コンストラクタ。
	 * @param name 名前
	 */
	public Car(String name) {
		this.name = name;
	}

	@Override
	public void move() {
		System.out.println(this.name + "は前進しました。");
	}

	@Override
	public void back() {
		System.out.println(this.name + "は後退しました。");
	}
}

P201/P201.java

/**
 * インターフェイスを確認します。
 */
public class P201 {
	
	/**
	 * メインメソッド。
	 * @param args 引数
	 */
	public static void main(String[] args) {
		// Car型インスタンスを作成し、Car型変数に紐づける
		Car car = new Car("白い車");
		car.move();
		car.back();
		
		// Car型インスタンスを作成し、Movable型変数に紐づける
		Movable movable = new Car("赤い車");
		movable.move();
		movable.back();
	}
}

実行結果は以下の通り。

白い車は前進しました。
白い車は後退しました。
赤い車は前進しました。
赤い車は後退しました。

イメージとしては以下のような感じです。このイメージの中に本来はメソッドも記述すべきですが、省略しています。

インターフェイスを作る

インターフェイスと多態性

インターフェイスと多態性

抽象クラスを用いたときのように、インターフェイスを用いて多態性を実現することができます。抽象クラスにはクラスの継承関係がありますが、インターフェイスの場合は継承関係を気にせずに実装できる利点があり、遠く離れたクラス同士で多態性を実現できる時があります。

ここでは、Animalクラスを継承した Birdクラスを継承したカラス(Crow)クラスと、飛行機(Airplane)クラスとの関係について考えていきます。なお、カラスと飛行機は、ともに「飛ぶ」ことが可能だとします。

インターフェイスを利用しない場合

インターフェイスを利用しない場合。Animalクラス、Birdクラス、Crowクラスは M601プロジェクトのものを利用しています。Airplaneクラスは新たに作成しています。

ソースコードは以下の通り。

P202/Animal.java

/**
 * 動物を表す抽象クラスです。
 */
public abstract class Animal {
	/**
	 * 名前。
	 */
	protected String name;
	/**
	 * 鳴く回数。
	 */
	protected int cryCount;
	
	/**
	 * 名前を設定します。
	 * @param name 名前
	 */
	public void setName(String name) {
		this.name = name;
	}
	
	/**
	 * 鳴く回数を設定します。
	 * @param cryCount 鳴く回数
	 */
	public void setCryCount(int cryCount) {
		this.cryCount = cryCount;
	}
	
	/**
	 * 鳴きます。
	 */
	public abstract void cry();
}

P202/Bird.java

/**
 * 鳥を表す抽象クラスです。
 */
public abstract class Bird extends Animal {
	
	/**
	 * 飛びます。
	 */
	public void fly() {
		System.out.println(this.name + "は飛びました。");
	}
}

P202/Crow.java

/**
 * 犬を表すクラスです。
 */
public class Crow extends Bird {
	/**
	 * コンストラクタ。
	 */
	public Crow() {
		this(1);
	}
	
	/**
	 * コンストラクタ。
	 * @param cryCount 鳴く回数
	 */
	public Crow(int cryCount) {
		this.setName("名無しのカラス");
		this.setCryCount(cryCount);
	}
	
	@Override
	public void cry() {
		System.out.print(this.name + "「");
		for(int i = 0; i < this.cryCount; i ++) {
			System.out.print("カー");
		}
		System.out.println("」");
	}
	
	@Override
	public String toString() {
		return "[Crow] name:" + this.name + ", cryCount:" + this.cryCount;
	}
}

P202/Airplane.java

/**
 * 飛行機を表すクラスです。
 */
public class Airplane {
	
	/**
	 * 飛びます。
	 */
	public void fly() {
		System.out.println("飛行機は飛びました。");
	}
}

P202/P202.java

/**
 * インターフェイスと多態性を確認します(インターフェイスを使用しない場合)。
 */
public class P202 {
	
	public static void main(String[] args) {
		Crow crow1 = new Crow();
		Crow crow2 = new Crow(5);
		
		Airplane airplane1 = new Airplane();
		Airplane airplane2 = new Airplane();
		
		crow1.fly();
		crow2.fly();
		airplane1.fly();
		airplane2.fly();
	}
}

実行結果は以下の通り。

名無しのカラスは飛びました。
名無しのカラスは飛びました。
飛行機は飛びました。
飛行機は飛びました。

イメージとしては以下のような感じです。このイメージの中に本来はメソッドも記述すべきですが、省略しています。

インターフェイスと多態性 (1)

インターフェイスを利用した場合

Animalクラス、Crowクラスは、P202プロジェクトのものをそのまま利用しています。Birdクラス、Airplaneクラスは P202プロジェクトのものを改良しています。Flyableインターフェイスは新たに作成しています。

ソースコードは以下の通り。

P203/Flyable.java

/**
 * 飛行可能なことを表すインターフェイスです。
 */
public interface Flyable {
	
	/**
	 * 飛びます。
	 */
	public abstract void fly();
}

P203/Animal.java

/**
 * 動物を表す抽象クラスです。
 */
public abstract class Animal {
	/**
	 * 名前。
	 */
	protected String name;
	/**
	 * 鳴く回数。
	 */
	protected int cryCount;
	
	/**
	 * 名前を設定します。
	 * @param name 名前
	 */
	public void setName(String name) {
		this.name = name;
	}
	
	/**
	 * 鳴く回数を設定します。
	 * @param cryCount 鳴く回数
	 */
	public void setCryCount(int cryCount) {
		this.cryCount = cryCount;
	}
	
	/**
	 * 鳴きます。
	 */
	public abstract void cry();
}

P203/Bird.java

/**
 * 鳥を表す抽象クラスです。
 */
public abstract class Bird extends Animal implements Flyable {
	
	@Override
	public void fly() {
		System.out.println(this.name + "は飛びました。");
	}
}

P203/Crow.java

/**
 * 犬を表すクラスです。
 */
public class Crow extends Bird {
	/**
	 * コンストラクタ。
	 */
	public Crow() {
		this(1);
	}
	
	/**
	 * コンストラクタ。
	 * @param cryCount 鳴く回数
	 */
	public Crow(int cryCount) {
		this.setName("名無しのカラス");
		this.setCryCount(cryCount);
	}
	
	@Override
	public void cry() {
		System.out.print(this.name + "「");
		for(int i = 0; i < this.cryCount; i ++) {
			System.out.print("カー");
		}
		System.out.println("」");
	}
	
	@Override
	public String toString() {
		return "[Crow] name:" + this.name + ", cryCount:" + this.cryCount;
	}
}

P203/Airplane.java

/**
 * 飛行機を表すクラスです。
 */
public class Airplane implements Flyable {

	@Override
	public void fly() {
		System.out.println("飛行機は飛びました。");
	}
}

P203/P203.java

/**
 * インターフェイスと多態性を確認します。
 */
public class P203 {
	
	public static void main(String[] args) {
		Flyable[] flyables = new Flyable[] {
			new Crow(),
			new Crow(5),
			new Airplane(),
			new Airplane(),
			new Crow(3),
			new Airplane(),
		};
		
		for(int i = 0; i < flyables.length; i ++) {
			flyables[i].fly();
		}
	}
}

実行結果は以下の通り。

名無しのカラスは飛びました。
名無しのカラスは飛びました。
飛行機は飛びました。
飛行機は飛びました。
名無しのカラスは飛びました。
飛行機は飛びました。

先にで作成した Birdクラスの flyメソッドと、Airplaneクラスの flyメソッドは、たまたまメソッド名が一致しているだけでした。今回、Flyableというインターフェイスに flyという抽象メソッドを宣言し、両クラスが Flyableインターフェイスを実装したことで、意図して一致させているということになります。

その結果として、多態性が実現できています。

イメージとしては以下のような感じです。このイメージの中に本来はメソッドも記述すべきですが、省略しています。

インターフェイスと多態性 (2)

複数のインターフェイスを実装する

Javaでは、多重継承は認められませんが、インターフェイスは幾つでも同時に実装することができまます。予約語 implementsの後ろに、実装したいインターフェイスをコンマで区切って並べるだけです。

M203プロジェクトの Airplaneクラスを利用して複数のインターフェイスを実装してみることにします。ここでは、Flyableインターフェイスと Sendableインターフェイスを作成し、Airplaneクラスでこれらのインターフェイスを実装しています。

ソースコードは以下の通り。

P204/Flyable.java

/**
 * 飛行可能なことを表すインターフェイスです。
 */
public interface Flyable {
	
	/**
	 * 飛びます。
	 */
	public abstract void fly();
}

P204/Sendable.java

/**
 * メッセージを送信可能であることを表すインターフェイスです。
 */
public interface Sendable {
	
	/**
	 * メッセージを送信します。
	 */
	public abstract void send();
}

P204/Airplane.java

/**
 * 飛行機を表すクラスです。
 */
public class Airplane implements Flyable, Sendable {

	@Override
	public void fly() {
		System.out.println("飛行機は飛びました。");
	}
	
	@Override
	public void send() {
		System.out.println("飛行機はメッセージを送信しました。");
	}
}

P204/P204.java

/**
 * 複数のインターフェイスの実装を確認します。
 */
public class P204 {
	
	/**
	 * メインメソッド。
	 * @param args 引数
	 */
	public static void main(String[] args) {
		Airplane airplane = new Airplane();
		Flyable flyable = airplane;
		Sendable sendable = airplane;
		
		airplane.fly();
		airplane.send();
		
		flyable.fly();
		// flyable.send(); // ビルドエラー
		
		// sendable.fly(); // ビルドエラー
		sendable.send();
	}
}

実行結果は以下の通り。

飛行機は飛びました。
飛行機はメッセージを送信しました。
飛行機は飛びました。
飛行機はメッセージを送信しました。

このプログラムでは Airplane型インスタンスを 1個生成しています。参照型変数の型によって、利用可能なメソッドが限定されることが分かります。

イメージとしては以下のような感じです。このイメージの中に本来はメソッドも記述すべきですが、省略しています。

複数のインターフェイスの実装

インターフェイスを継承するインターフェイス

複数のインターフェイスを継承した、新しいインターフェイスを作成することもできます。

ソースコードは以下の通り。

P205/Sendable.java

/**
 * メッセージを送信可能であることを表すインターフェイスです。
 */
public interface Sendable {
	
	/**
	 * メッセージを送信します。
	 */
	public abstract void send();
}

P205/Receivable.java

/**
 * メッセージが受信可能であることを表すインターフェイスです。
 */
public interface Receivable {
	
	/**
	 * メッセージを受け取ります。
	 * @param message メッセージ
	 */
	public abstract void receive(String message);
}

P205/Communicatable.java

/**
 * メッセージの送受信が可能であることを表すインターフェイスです。
 */
public interface Communicatable extends Sendable, Receivable {
	
}

P205/Flyable.java

/**
 * 飛行可能なことを表すインターフェイスです。
 */
public interface Flyable {
	
	/**
	 * 飛びます。
	 */
	public abstract void fly();
}

P205/Airplane.java

/**
 * 飛行機を表すクラスです。
 */
public class Airplane implements Flyable, Communicatable {

	@Override
	public void fly() {
		System.out.println("飛行機は飛びました。");
	}
	
	@Override
	public void send() {
		System.out.println("飛行機はメッセージを送信しました。");
	}

	@Override
	public void receive(String message) {
		System.out.println("飛行機はメッセージ「" + message + "」を受信しました。");
	}
}

P205/P205.java

/**
 * インターフェイスの継承を確認します。
 */
public class P205 {
	
	/**
	 * メインメソッド。
	 * @param args 引数
	 */
	public static void main(String[] args) {
		// Airplane型インスタンスを生成し、参照型変数に紐づけます
		Airplane airplane = new Airplane();
		Flyable flyable = airplane;
		Communicatable communicatable = airplane;
		Sendable sendable = airplane;
		Receivable receivable = airplane;
		
		airplane.fly();
		airplane.send();
		airplane.receive("こんにちは");
		
		flyable.fly();
		// flyable.send(); // ビルドエラー
		// flyable.receive("こんにちは"); // ビルドエラー
		
		// communicatable.fly(); // ビルドエラー
		communicatable.send();
		communicatable.receive("こんにちは");
		
		// sendable.fly(); // ビルドエラー
		sendable.send();
		// sendable.receive("こんにちは"); // ビルドエラー
		
		// receivable.fly(); // ビルドエラー
		// receivable.send(); // ビルドエラー
		receivable.receive("こんにちは");
	}
}

実行結果は以下の通り。

飛行機は飛びました。
飛行機はメッセージを送信しました。
飛行機はメッセージ「こんにちは」を受信しました。
飛行機は飛びました。
飛行機はメッセージを送信しました。
飛行機はメッセージ「こんにちは」を受信しました。
飛行機はメッセージを送信しました。
飛行機はメッセージ「こんにちは」を受信しました。

インターフェイス Sendableと Receivableを継承する、新しいインターフェイス Communicatableを作成し、使用しています。

このプログラムでは Airplane型インスタンスを 1個生成しています。参照型変数の型によって、利用可能なメソッドが限定されることが分かります。

Javaでは多重継承は認められていないので、クラスを継承(extedns)する場合、スーパークラスをひとつしか指定できません。しかし、インターフェイスの場合は、複数のインターフェイスを指定して継承(extends)することができます。

イメージとしては以下のような感じです。このイメージの中に本来はメソッドも記述すべきですが、省略しています。

インターフェイスを継承するインターフェイス

最終更新: 2013/03/04 , 公開: 2013/03/04
▲top