予約語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();
}
}
実行結果は以下の通り。
名無しのカラスは飛びました。 名無しのカラスは飛びました。 飛行機は飛びました。 飛行機は飛びました。
イメージとしては以下のような感じです。このイメージの中に本来はメソッドも記述すべきですが、省略しています。

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インターフェイスを実装したことで、意図して一致させているということになります。
その結果として、多態性が実現できています。
イメージとしては以下のような感じです。このイメージの中に本来はメソッドも記述すべきですが、省略しています。

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)することができます。
イメージとしては以下のような感じです。このイメージの中に本来はメソッドも記述すべきですが、省略しています。
