Java学習者の中には、インターフェースと抽象クラスという名前自体は知っているものの、2つの似た機能を曖昧にしか理解出来ていない方も多いのではないでしょうか。
本記事では、インターフェースとは何なのかといった基本的な概要から使い方、抽象クラスとの違いまでサンプルコードを掲載しながらご紹介していきます。
目次
Javaのインターフェースとは
インターフェース(interface)は、クラス内のメソッドに具体的な処理を記述せず、メソッド名や戻り値といった仕様のみを定義したものです。
インターフェースの概要
インターフェースは単独で処理を実行することは出来ません。
インターフェースに定義された機能を利用するには、別のクラスで「実装」する必要があります。
インターフェースの使い方
Javaではインターフェースを定義した上で、利用する際は「implements」を使用します。
インターフェースの定義
interface インターフェース名 { }
インターフェースの利用
アクセス修飾子 class クラス名 implements インターフェース名 { }
インターフェースと抽象クラスの違いを把握しよう
インターフェースと似た性質を持つ機能に「抽象クラス」があり、初心者の方は混乱してしまいがちです。
それぞれの違いについても確認しておきましょう。
抽象クラスとは
抽象クラス(abstract)は、具体的な処理内容が記述されていないメソッドが1つ以上存在するクラスのことを指します。
抽象メソッドが1つ以上存在していれば、具体的な処理を記述したメソッドが存在しても構いません。
抽象クラスは直接インスタンス化することが出来ず、利用するためには継承クラスが必要となります。
インターフェースと抽象クラスとの違い
ここまでインターフェースと抽象クラスについて説明してきましたが、どちらも似た機能で分かりにくいですよね。
ここでは主な機能の違いをピックアップしてご紹介します。
- 多重継承の違い
- アクセス修飾子の違い
- 変数定義の違い
- メソッド定義の違い
多重継承の違い
インターフェースは多重継承が出来るのに対し、抽象クラスでは多重継承が出来ない違いがあります。
多重継承とは、利用する側のクラスで複数のインターフェースやクラスを継承することを指します。
インターフェースで下記のような記述は可能ですが
アクセス修飾子 class クラス名 implements インターフェース1, インターフェース2 { }
抽象クラスで下記のような記述は出来ません。
アクセス修飾子 class クラス名 extends 抽象クラス1, 抽象クラス2 { }
アクセス修飾子の違い
インターフェースではアクセス修飾子が「public」に限定されるのに対し、抽象クラスでは「public」「protected」の利用が可能です。
インターフェースはどこからでも利用出来る指定しか出来ませんが、抽象クラスの場合パッケージ内に限定(protected)しての公開設定も可能です。
変数定義の違い
インターフェースの場合クラス変数しか定義することが出来ないのに対し、抽象クラスではクラス変数はもちろん、インスタンス変数など各種変数の定義が可能です。
またインターフェースでは継承クラスで上書きすることが出来ない制約も加わります。
メソッド定義の違い
上述したようにインターフェースではメソッドの定義しか出来ないのに対し、抽象クラスでは抽象メソッドが1つ以上存在すれば具体的な処理を記述したメソッドを定義することも可能です。
ただし、Java8の言語拡張によりインターフェースでも「default」メソッドとして記述すれば、具体的な処理内容まで記述出来るようになりました。
インターフェースの使い方をJavaのサンプルで確認しよう
ここからはサンプルコードでインターフェースの具体的な使い方を確認していきたいと思います。
インターフェースの基本
まずは1つのインターフェースを使用する基本の使い方をご紹介します。
// 実行用クラス public class Main { public static void main(String[] args) { Businessman man1 = new Businessman(); man1.program(); } } // インターフェース interface Programmer { String name = "プログラマー"; void program(); } // インターフェースの実装用クラス class Businessman implements Programmer { public void program() { System.out.println(name + "はシステム開発が出来ます。"); } }
実行結果が下記です。
プログラマーはシステム開発が出来ます。
11~15行目の処理がインターフェースを定義している部分で、クラス変数と処理内容を記述していない状態のメソッドを定義しました。
18~22行目が実際にインターフェースを使用するクラスを定義しており、「program」というメソッドに具体的な処理となるコンソール出力を記述しています。
2~8行目は実際にプログラムを実行するためのクラスで、作成した「Businessman」クラスを使用して処理を実行しています。
defaultメソッドでインターフェースに直接処理を記述
上記のサンプルをJava8より利用可能な「default」メソッドを使用して書き換えてみましょう。
// 実行用クラス public class Main { public static void main(String[] args) { Businessman man1 = new Businessman(); man1.program(); } } // インターフェース interface Programmer { String name = "プログラマー"; default public void program() { System.out.println(name + "はシステム開発が出来ます。"); }; } // インターフェースの実装用クラス class Businessman implements Programmer { // オーバーライドしないため処理の記述なし }
実行結果が下記です。
プログラマーはシステム開発が出来ます。
記述方法が異なるだけで実行結果は全く同じです。
今回は11~17行目のインターフェース定義の中で、14行目に記述したdefaultにより具体的な処理内容が記述出来るようになっています。
20~22行目のクラス定義では、インターフェースの処理をそのまま利用するため、何も記述していません。
インターフェースは直接利用することが出来ないため、何も処理を記述しないとしても実装クラスを定義する必要があります。
複数インターフェースの実装
抽象クラスとの違いで紹介したように、インターフェースは多重継承が可能です。
実際にサンプルで確認してみましょう。
// 実行用クラス public class Main { public static void main(String[] args) { Businessman man1 = new Businessman(); man1.program(); man1.sale(); } } // インターフェース interface Programmer { String name = "プログラマー"; default public void program() { System.out.println(name + "はシステム開発が出来ます。"); }; } // インターフェース interface Sales { String name = "営業"; void sale(); } // インターフェースの実装用クラス class Businessman implements Programmer, Sales { public void sale( ) { System.out.println("営業職も兼業しています。"); } }
実行結果が下記です。
プログラマーはシステム開発が出来ます。 営業職も兼業しています。
28~32行目で定義した実装クラスには「Progranner」と「Sales」のインターフェースが両方継承されています。
「Programmer」はdefaultで処理を記述しているため、実装用クラス(Businessman)にはメソッドのオーバーライドは不要ですが、「Sales」インターフェースのメソッドはオーバーライドが必要な点はしっかりと確認しておきましょう。
さいごに: Javaのインターフェースとは何かを理解してプログラマーとしてのスキルを高めよう
本記事では、Javaのインターフェースとは何かについてご紹介してきました。
インターフェースは頻繁に利用される機能ではありますが、言葉だけでは分かりにくいため、実際に何度も使ってみることで自分なりに理解を深めることが重要です。
今回のサンプルコードは基本中の基本と呼べる内容なので、様々なサンプルコードに触れてみて自分でも利用することでインターフェースを使いこなせるよう学習していきましょう。
具体的な使い方については後ほどサンプルコードで解説します。