手を動かして学ぶ Java入門 (インタフェースの基本)
環境構築不要! ブラウザから直接コードを実行できます。
本記事では、インタフェースの基本について学びます。
15分くらいで、さくっと終わる記事をめざしています。
シリーズ一覧
- シリーズ
- 手を動かして学ぶ Java入門 (Hello world 編)
- 手を動かして学ぶ Java入門 (数値と演算)
- 手を動かして学ぶ Java入門 (数値と変数)
- 手を動かして学ぶ Java入門 (コメントの書き方)
- 手を動かして学ぶ Java入門 (文と式の違い)
- 手を動かして学ぶ Java入門 (if文)
- 手を動かして学ぶ Java入門 (if-else文、if-elseif文)
- 手を動かして学ぶ Java入門 (文字列の連結)
- 手を動かして学ぶ Java入門 (while文)
- 手を動かして学ぶ Java入門 (break文)
- 手を動かして学ぶ Java入門 (continue文)
- 手を動かして学ぶ Java入門 (for文)
- 手を動かして学ぶ Java入門 (クラスの超基本)
- 手を動かして学ぶ Java入門 (クラス・メソッド)
- 手を動かして学ぶ Java入門 (クラス・フィールド)
- 手を動かして学ぶ Java入門 (クラス・コンストラクタ)
- 手を動かして学ぶ Java入門 (文字列クラス)
- 手を動かして学ぶ Java入門 (静的メソッド)
- 手を動かして学ぶ Java入門 (静的フィールド)
- 手を動かして学ぶ Java入門 (定数の定義)
- 手を動かして学ぶ Java入門 (クラス継承の超基本)
- 手を動かして学ぶ Java入門 (メソッドのオーバーライド)
- 手を動かして学ぶ Java入門 (メソッドのオーバーロード)
- 手を動かして学ぶ Java入門 (thisキーワード)
- 手を動かして学ぶ Java入門 (superキーワード)
- 手を動かして学ぶ Java入門 (抽象クラスと抽象メソッド)
- 手を動かして学ぶ Java入門 (インタフェースの基本)
続きは近日公開予定!
はじめに
この記事は paiza.IO の「Online Java compiler」を利用しています。
2025/1/27 現在、上記環境の Java バージョンは 18 です。(paiza.IO利用ガイド)
実行したコードは paiza.IO で保存および公開されることがあります。
そのため、個人情報などの機密性の高い情報は、コードとして入力しないようにご注意ください。
詳細は paiza.IO の利用規約およびプライバシーポリシーをご確認ください。
抽象クラスと抽象メソッドのおさらい
抽象クラスとは、
- 1つ以上の 抽象メソッド を宣言したクラス
のことです。
そして、抽象メソッドとは、
- 実装のないメソッド
のことです。
「実装」とは、具体的に 記述されたコードになります。
実際の例で見てみましょう。
抽象クラスの AbstractSample クラスを宣言してみます。
抽象クラスと抽象メソッドを宣言するには、abstract キーワードを使うのでしたね。
public abstract class AbstractSample {
^^^^^^^^ <--- ★この部分!
public abstract void print();
^^^^^^^^ <--- ★この部分!
}
print メソッドは抽象メソッドです。
通常のメソッドと違い、実装である { ... } の記述がなくて、いきなりセミコロン(;) で終わらせています。
public abstract void print();
^ <--- 実装がない
詳しくは 前回の記事 もよろしければご参照ください。
インタフェース
インタフェースとは、簡単にいうと…
- 抽象メソッドだけで構成されたクラス
のことです。
つまりインタフェースは実装を持ちません。
一方、抽象クラスは通常のメソッドを宣言しても OK です。
つまり実装を持つこともできます。
これがインタフェースと抽象クラスの大きな違いです。
インタフェースはオブジェクト指向プログラミングにおいて大事な役割を持ちます。
特に、後述する 多重実装 できることが大きなメリットです。
最初のうちは「わざわざインタフェースを使わなくてもよいのでは…?」と感じることもあるかと思います。
Java のことが分かってきて、オブジェクト指向もなんとなく理解して…
デザインパターン なんかを使い始めるとメリットが理解できてくる … かもしれません。
あせらずに、ゆっくりと理解していければよいのかな、と思います。
宣言
さっそくインタフェースのコード例を見てみましょう。
Sample という名前のインタフェースを宣言してみます。
public interface Sample {
void print();
}
こんな感じですね。
クラスの宣言とだいたい同じです。
ただし、class の代わりに interface キーワードを使うのがポイントです。
public interface Sample {
^^^^^^^^^ <--- ★この部分!
...
}
もう1つ、抽象メソッドの宣言には、
- public
- abstract
を書く必要はありません。
省略しても、暗黙的に public と abstract を書いたことと同じになります。
つまり、
public interface Sample {
void print();
}
↑これと…
public interface Sample {
public abstract void print();
}
↑これは同じ意味になります。
一般的には、インタフェースの抽象メソッドは public と abstract を省略することが多いようです。
補足
- 「通常のクラス」や「抽象クラス」のメソッドについては、public と abstract を省略すると違う意味になるのでご注意ください。
抽象メソッドのオーバーライド
さて、インタフェースには実装がありません。
そのまま new 演算子でインスタンスを生成しようとするとエラーになります。
public interface Sample {
void print();
}
Sample sample = new Sample();
実際にプログラムを動かして確認してみましょう。
コードは変更せずに、そのまま「実行(Ctrl-Enter)」ボタンを押してください。
注意:コードは2ファイルあります。上部のタブで切り替え可能です。
(表示がおかしいときは「コードの再読み込み」ボタンを押してみてください)
いかがでしたでしょうか? 下記のようなコンパイルエラーが出たら成功です。
Main.java:4: error: Sample is abstract; cannot be instantiated
Sample sample = new Sample();
^
1 error
"Sample is abstract; cannot be instantiated" とは、意訳すると
- Sample はインタフェース(抽象型) です。よってインスタンス化できません。
という感じです。
抽象クラスと同じで、インタフェースを使うには抽象メソッドを オーバーライド する必要があります。
ただし、インタフェースの場合は継承(extends) ではなく、実装(implements) することになります。
といっても身構えなくても大丈夫。使い方は継承と同じです。
それでは、さっそく抽象メソッドの print メソッドをオーバーライドしてみましょう。
オーバーライドするには、インタフェースを実装(implements) します。
public interface Sample {
void print();
}
public class SampleImpl implements Sample {
@Override
public void print() {
System.out.println("オーバーライド!");
}
}
Sample インタフェースを実装した SampleImpl クラスを作ってみました。
(ちなみに SampleImpl の Impl は Implement を短くしたものです。もちろん他の名前でも OK です)
public class SampleImpl implements Sample {
^^^^^^^^^^ <--- ★継承とは違うので注意!
...
}
実際にプログラムを動かして確認してみましょう。
結果がどうなるか予想してから「実行(Ctrl-Enter)」ボタンを押してください。
注意:コードは3ファイルあります。上部のタブで切り替え可能です。
(表示がおかしいときは「コードの再読み込み」ボタンを押してみてください)
いかがでしたでしょうか? 「出力」のところに
オーバーライド!
と表示されたら成功です。
無事に抽象メソッドをオーバーライドできました。
定数の定義
インタフェースには通常のフィールドは宣言できません。
ただし、定数だけは宣言できます。
(定数については こちらの記事 でも解説しています)
public interface Sample {
double PI = 3.14;
}
上記のコード例では、円周率 3.14 を PI という名前の定数で宣言しています。
ただし、通常のクラスで定数を宣言するのとは違う点があります。
インタフェースで定数を宣言するとき、
- public
- static
- final
を書く必要はありません。
暗黙的に、public と static と final は書いたことと同じになります。
つまり、
public interface Sample {
double PI = 3.14;
}
↑これと…
public interface Sample {
public static final double PI = 3.14;
}
↑これは同じ意味になります。
一般的には、インタフェースで定数を宣言するときは public と static、final を省略することが多いようです。
補足
- 「通常のクラス」や「抽象クラス」のフィールド宣言については、public と static、final を省略すると違う意味になるのでご注意ください。
多重継承と多重実装
1つのクラスが複数のクラスを継承することを 多重継承 といいます。
ただし、Java では多重継承はサポートしていません。
つまり、通常のクラスや抽象クラスは、それらを複数継承(extends) することはできません。
継承できるのは1つだけです。
// 通常のクラス
public class Sample1 {
}
// 通常のクラス
public class Sample2 {
}
// これは OK
public class SubSample extends Sample1 {
}
// これは NG
public class SubSample extends Sample1, Sample2 {
}
しかし、インタフェースを複数継承 … 正確には複数実装(implements) することができます。
// インタフェース
public interface Sample1 {
}
// インタフェース
public interface Sample2 {
}
// これは OK
public class SampleImpl implements Sample1 {
}
// これも OK
public class SampleImpl implements Sample1, Sample2 {
}
多重実装できることは、インタフェースの大きなメリットとなります。
補足
インタフェースは本来、実装を含みません。
Java も当初はそのような仕様でした。
しかし、Java 8 からはインタフェースに
- default メソッド
- static メソッド
が定義できるようになりました。
これにより、限定的ですがインタフェースに実装を含めることができます。
もし、そのあたりの話が気になるかたは、下記の関連記事もご参照ください。
応用問題
【問題】
まずは、下記のプログラムをそのまま「実行(Ctrl-Enter)」してみましょう。
結果はコンパイルエラーになったはずです。
SampleImpl.java:1: error: SampleImpl is not abstract and does not override abstract method getValue1() in Sample1
public class SampleImpl implements Sample1, Sample2 {
... 省略 ...
これは SampleImpl クラスで、抽象メソッドの getValue1 と getValue2 メソッドをオーバーライドしていないためです。
そこで問題です。
SampleImpl クラスで getValue1 と getValue2 メソッドをオーバーライドして、プログラムを実行すると、
getValue1 = 123
getValue2 = 456
と「出力」に表示されようにしてください。
SampleImpl クラスに getValue1 と getValue2 メソッドをオーバーライドしてから「実行(Ctrl-Enter)」してみましょう。
(修正するのは SampleImpl クラスだけです)
注意:コードは4ファイルあります。上部のタブで切り替え可能です。
(表示がおかしいときは「コードの再読み込み」ボタンを押してみてください)
無事に、
getValue1 = 123
getValue2 = 456
と出力されましたでしょうか?
もし解けなかった場合は、下記の回答例をご参照ください。
回答例
【コード】
public class SampleImpl implements Sample1, Sample2 {
// ここに getValue1 と getValue2 をオーバーライドしてください。
@Override
public int getValue1() {
return 123;
}
@Override
public int getValue2() {
return 456;
}
public void print() {
System.out.println("getValue1 = " + getValue1());
System.out.println("getValue2 = " + getValue2());
}
}
※ Main.java, Sample1.java, Sample2.java は書き換えません。
【出力】
getValue1 = 123
getValue2 = 456
まとめ
インタフェースとは、簡単にいうと…
- 抽象メソッドだけで構成されたクラス
のことです。
つまり実装を持ちません。
インタフェースはオブジェクト指向プログラミングにおいて大事な役割を持ちます。
多重実装 できることが大きなメリットとなります。
ぜひ有効に活用していきたいですね。
それでは次回もお楽しみに!
関連記事
- シリーズ
- 手を動かして学ぶ Java入門 (Hello world 編)
- 手を動かして学ぶ Java入門 (数値と演算)
- 手を動かして学ぶ Java入門 (数値と変数)
- 手を動かして学ぶ Java入門 (コメントの書き方)
- 手を動かして学ぶ Java入門 (文と式の違い)
- 手を動かして学ぶ Java入門 (if文)
- 手を動かして学ぶ Java入門 (if-else文、if-elseif文)
- 手を動かして学ぶ Java入門 (文字列の連結)
- 手を動かして学ぶ Java入門 (while文)
- 手を動かして学ぶ Java入門 (break文)
- 手を動かして学ぶ Java入門 (continue文)
- 手を動かして学ぶ Java入門 (for文)
- 手を動かして学ぶ Java入門 (クラスの超基本)
- 手を動かして学ぶ Java入門 (クラス・メソッド)
- 手を動かして学ぶ Java入門 (クラス・フィールド)
- 手を動かして学ぶ Java入門 (クラス・コンストラクタ)
- 手を動かして学ぶ Java入門 (文字列クラス)
- 手を動かして学ぶ Java入門 (静的メソッド)
- 手を動かして学ぶ Java入門 (静的フィールド)
- 手を動かして学ぶ Java入門 (定数の定義)
- 手を動かして学ぶ Java入門 (クラス継承の超基本)
- 手を動かして学ぶ Java入門 (メソッドのオーバーライド)
- 手を動かして学ぶ Java入門 (メソッドのオーバーロード)
- 手を動かして学ぶ Java入門 (thisキーワード)
- 手を動かして学ぶ Java入門 (superキーワード)
- 手を動かして学ぶ Java入門 (抽象クラスと抽象メソッド)
- 手を動かして学ぶ Java入門 (インタフェースの基本)