はじめに
この章では、インスタンス化を行うことができる具象クラス、抽象メソッドを定義することができる抽象クラス、クラスにおいて仕様の役割を持つインターフェースについて、それぞれの特徴と定義の方法を学習します。
目次
- 抽象クラス
- 抽象クラスの定義
- 抽象クラスの実装
- 抽象クラスのポリモーフィズム
- インターフェース
- インターフェースの定義
- インターフェースの実装
- インターフェースのポリモーフィズム
- 章のまとめ
目標
抽象クラスとインターフェースについて理解すること。
抽象クラス
抽象クラス
とは、他のクラス
により、継承されることを前提に定義されたクラス
です。そのため、抽象クラス
はインスタンス化
することができません。
抽象クラス
は、クラスの設計をおこなう際に、まだ処理内容が明確に決まってない
場合に、概要だけ
を抽象メソッドとして定義し、そのクラスを継承したサブクラス内
で詳細な処理を定義する
設計手法です。
抽象クラスの定義
抽象クラス
を定義するためには、クラスの宣言にabstract
キーワードを付けます。abstract
キーワードをつけることにより、定義が完結していないことを示します。メソッド内の処理定義が無く
、末尾にセミコロン( ; )
をつけたメソッドを抽象メソッド
といいます。抽象メソッド
はメソッドの宣言にabstract
キーワードを付けます。
一方、メソッド内に、処理が定義されているメソッド
を具象メソッド
(通常のメソッド)といいます。抽象クラス内
では、抽象メソッド
や具象メソッド
のどちらでも定義可能です。
尚、抽象クラス
(abstract
キーワードが付与されたクラス)は定義が不完全な為、newでオブジェクトを作成(インスタンス化)する
ことはできません。
抽象クラスの定義例
以下は抽象クラスと抽象メソッドの例です。
抽象メソッドを持たない抽象クラス
の定義例//抽象クラス
abstract class Sample01{
//具象メソッド
public void A(){
System.out.println("A method");
}
}抽象メソッドと具象メソッドを含む抽象クラス
の定義例//抽象クラス
abstract class Sample01{
//具象メソッド
public void A(){
System.out.println("A method");
}
//抽象メソッド
abstract void B();
}抽象メソッドのみの抽象クラス
の定義例//抽象クラス
abstract class Sample01{
//抽象メソッド
abstract void B();
}何もメソッドが定義していない抽象クラス
の定義例//抽象クラス
abstract class Sample01{
}
抽象クラスの実装
抽象クラス
は、サブクラス
で継承(extends)
し、実装
して利用します。
※抽象クラス
のメソッド
をオーバーライド
し、具体的な処理を記述することを実装する
といいます。
以下、実装する際の構文です。
抽象メソッド
は不完全なので、スーパークラスで定義されている全ての抽象メソッド
はサブクラス
で実装
しなければなりません。もし、サブクラス
で一部のメソッド
を実装しなかった
場合、コンパイルエラー
になります。
例題(抽象クラスの利用①)
以下サブクラスで実装している例です。
抽象クラスおよびサブクラスを定義し、実行結果を確認してください。
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter10 |
クラス名 | Greeting |
package chapter10; |
抽象クラス
を作成するときはabstract
キーワードを使用します。またメソッド
に関しても抽象メソッド
という形式で書きます。
尚、abstract
キーワードはアクセス修飾子の前
に書いても良いです。
package chapter10; |
抽象クラス
を継承したサブクラス
では、必ずabstract
キーワードが付与されているメソッドをオーバーライド
(実装)します。
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter10 |
クラス名 | JapaneseGreeting |
継承 | Greeting |
package chapter10; |
サブクラスで抽象メソッド
をオーバーライド
(実装)しないとコンパイルエラー
になります。
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter10 |
クラス名 | GreetingExec |
package chapter10; |
コンパイル例:> javac chapter10¥Greeting.java
> javac chapter10¥JapaneseGreeting.java
> javac chapter10¥GreetingExec.java
実行例:> java chapter10.chapter10¥GreetingExec
言語:Japanese
挨拶:こんにちは
Greetingクラスがスーパークラスであり、抽象クラスとして定義されています。JapaneseGreetingクラスがGreetingクラスを継承し、抽象メソッドをオーバーライド(実装)しているサブクラスです。GreetingExecクラスは実行するためのクラスで、
Greetingクラスがスーパークラスであり、抽象クラスとして定義されています。JapaneseGreetingクラスをインスタンス化し、生成されたJapaneseGreetingオブジェクトをサブクラス型(JapaneseGreeting型)の変数jgへ代入し、jg.language()、jg.message()で実行しています。
例題(抽象クラスの利用②)
以下も、サブクラスで実装している例です。
抽象クラスおよびサブクラスを定義し、実行結果を確認してください。
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter10 |
クラス名 | Transport |
package chapter10; |
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter10 |
クラス名 | Car |
継承 | Transport |
package chapter10; |
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter10 |
クラス名 | Bass |
継承 | Transport |
package chapter10; |
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter10 |
クラス名 | TransportExec |
package chapter10; |
コンパイル例:> javac chapter10¥Transport.java
> javac chapter10¥Car.java
> javac chapter10¥Bass.java
> javac chapter10¥TransportExec.java
実行例:> java chapter10.TransportExec
Car:スピード : 100
止まります。
Bass:スピード : 50
止まります。
上記、イメージとしては以下のようになります。
Car型の変数cはCarオブジェクトを参照しています。Bass型の変数bはBassオブジェクトを参照しています。
c.run();とb.run();と実行することで、サブクラスでオーバーライドしたrun()メソッドを実行しています。
抽象クラスのポリモーフィズム
抽象クラス
はオブジェクトを作成することはできません。しかし、変数
として利用することはできます。変数
にはサブクラスのオブジェクト
の参照を代入
することが可能です。
抽象クラス
を変数
として利用すると、ポリモーフィズム
を実現
することができます。
例題(抽象クラスのポリモーフィズム)
以下は、抽象クラスでのポリモーフィズム
を実現しているプログラムの書き方です。
先ほど作成しました、TransportExecクラスを以下へ修正し、実行結果を確認してみましょう
※Transportクラス、Carクラス、Bassクラスはそのまま利用します。
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter10 |
クラス名 | TransportExec |
package chapter10; |
コンパイル例:> javac abstractInterfacePk¥TransportExec.java
実行例:> java abstractInterfacePk.TransportExec
Car:スピード : 100
止まります。
Bass:スピード : 50
止まります。
上記、イメージとしては以下のようになります。
変数tがTransport型(スーパクラス型)で、参照しているオブジェクトがCarオブジェクトやBassオブジェクト(サブクラス)になっています。(参照型のキャスト
) またrun()メソッドがオーバーライド
されており、ポリモーフィズム
を実現しています。
インターフェース
インターフェース
とは、操作方法を統一する
ために操作のアクセスの手段のみ
を定義
するプログラム部品のことです。
- 例)銀行のATM
銀行が異なっていてもATMの操作方法は統一されている
(振込、預け入れ、払い出し)
インターフェース
はクラスではありませんが、クラスに準じる
存在です。先ほど出てきました抽象クラス
と定義方法や使い方は似ていますが。クラスでは継承というところをインターフェース
では、実装
といいます。インターフェース
を実装
するクラスは、インターフェース
が定義している抽象メソッド
をオーバーライド
しなければなりません。
抽象クラス
と違う点
は、インターフェース
はクラスではないので、継承関係を考慮しなくても良い
ということです。
インターフェースの利用方法として、主に以下の2つがあります。
単一継承の欠点を補う利用方法
公開メソッドを明確にする手段としての利用方法
単一継承の欠点を補う利用方法
Java言語では、クラス
が継承
できるスーパークラス
は1つだけ
です。これを単一継承
といいます。例えば、次の図は同時に2つのクラス
をスーパークラス
にしてサブクラス
を作成
しようとしていますが、Java言語ではこのような多重継承
は許されません。
しかし、インターフェース
はクラスではないので、インターフェース
を実装する
ことで、複数のクラスを継承する
のと同じ
ような効果を上げる
ことができます。次の図は継承
の代わりにインターフェース
を実装
し、利用
しているケースを示しています。なお、図のようにインターフェースの実装
は、点線で表す
決まりになっていることも覚えておいてください。
インターフェース
は特定の機能
を実現するため
に利用します。特定の機能
の実現
を考え、そのために必要なメソッド
を抽象メソッドとして羅列しただけのもの
が、インターフェース
です。インターフェース
を実装
したクラスは、インターフェース
で定義
されている特定の機能
を自身のクラス
へ付加
するために使います。
公開メソッドを明確にする手段としての利用方法
インターフェース
は特定の機能を実現する
ために必要な定数
や抽象メソッド
の集まりです。また、インターフェース
で定義
する定数
や抽象メソッド
は、全てpublicなメンバ
だけから構成されます。
一方、クラス
においてpublicなメンバ
は外部に公開するメソッド
を意味し、インターフェース
を確認するたけで、クラスの機能
がわかります。そこで、クラスでpublic
にするメソッド
を全てインターフェース
として定義し、それを実装
してクラスを作成することが考えられます。この場合、インターフェース
を見るだけで利用できるメソッドが分かるので、文字通り、クラスの外観
とのインターフェース
を定義
する、ということになります。
このような使い方は、グループでひとつのシステムを開発する際に、システムに対する理解を共有するために利用されます。
インターフェースの定義
インターフェース
はクラスに準じる存在で次のように、定数
とメソッド
だけを定義
できます。インターフェースはinterface
というキーワードを使って定義します。
インターフェース
には定数
と抽象メソッド
だけを定義できる- クラス宣言には
abstract
が自動的
にコンパイラによって付加
される - 定数には
public static final
が自動的
にコンパイラによって付加
される - メソッドには
public abstract
が自動的
にコンパイラによって付加
される - インターフェースファイル名も
拡張子はjava
である extends
で他の複数のインターフェース
を拡張できる
インターフェースのコンパイル
ここではWithdrawという名前のインターフェースを参考に解説します。
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter10 |
インターフェース名 | Withdraw |
package chapter10; |
上記のように、インターフェース
には定数
と抽象メソッド
だけを定義します。
※Java SE8からはdefault
キーワードを利用すると、具象メソッドを定義することが可能になっています。
尚、以下のように定義することも可能です。
package chapter10; |
上記のインターフェースをコンパイル
すると以下のようになります。
package chapter10; |
上記をコンパイルすると、自動的
にpublicアクセス
とみなされるので、定義の中でpublic
をつける必要はありません。また、static
やfinal
、abstract
も、コンパイラが自動的に付加
してくれるので、定数
やメソッド
にプログラマ自身
が付加
する必要はありません(付けても間違えではないです。)
static
statc
をつけたメンバ変数やメソッドは、クラス変数
、クラスメソッド
といい、クラスに一つしかない固有なものです。インスタンス変数やインスタンスメソッドがオブジェクトの中に取り込まれて、各オブジェクトごとに存在するのに対して、クラス変数、クラスメソッドはクラス定義の中に一つだけ
存在します。クラス変数、クラスメソッドは静的メンバ
と呼ばれ、クラスから作成された全てのオブジェクトで共有
されます。したがって、クラスから作成されたオブジェクトは静的メンバ
に自由にアクセス
できます。
final
final
は「変更できない
」という意味の修飾子です。クラス、メソッド、変数の宣言時に使うことができます。
それぞれの効果は以下です。
対象 | 用例 | 効果 |
---|---|---|
クラス | final class Foo{} | 継承できない |
メソッド | final int addTashizan(){} | サブクラスでオーバーライドできない |
変数 | final int MAX = 1000; | 初期化時に代入した値を後から変更できない |
finalな変数
は宣言時に必ず値を代入
しなければなりません。代入した値を変更できない
ので、その数値の代わりに使うことができます。なお、変数をfinalにして定数として使う時は、大文字
を使うという慣例
があります。
extendsを伴うインターフェースの定義
インターフェースを定義する際、他のインターフェースを継承(extends)して作成することも可能です。
以下、インターフェースAはインターフェースXとインターフェースYを継承して、定義しています。
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter10 |
インターフェース名 | X |
package chapter10; |
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter10 |
インターフェース名 | Y |
package chapter10; |
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter10 |
インターフェース名 | A |
継承 | X、Y |
package chapter10; |
※インターフェースは多重継承
することが可能です。
尚、クラスへ実装する場合は、全てのインターフェースで定義されている抽象メソッドをオーバーライドしなければなりません。(次の項目の「インターフェースの実装」を参考にして下さい)
インターフェースの実装
インターフェースを実装するときはimplements
キーワードを利用します。そしてインターフェースで定義しているメソッドをオーバーライドします。正しく利用しないとコンパイルエラー
になります。
implements
キーワードを使ってインターフェースを実装
する- 一度に
複数のインターフェース
を実装
できる - クラスの
継承(extends)
と併用
できる
例題(インターフェースの実装)
以下はインターフェースの実装する例です。
コーディングし、実行結果を確認してみましょう。
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter10 |
インターフェース | Tools |
package chapter10; |
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter10 |
インターフェース | Var |
package chapter10; |
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter10 |
クラス | Parent |
package chapter10; |
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter10 |
クラス | Child |
継承 | Parent |
実装 | Tools , Var |
package chapter10; |
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter10 |
クラス | ChildExec |
package chapter10; |
コンパイル例:> javac chapter10¥Tools.java
> javac chapter10¥Var.java
> javac chapter10¥Parent.java
> javac chapter10¥Child.java
> javac chapter10¥ChildExec.java
実行例:> java chapter10.ChildExec
500
100
この例は一つのクラスを継承し、2つのインターフェース
を実装(imprements)
します。インターフェース
のメソッドは抽象メソッド
ですから、実装するChildクラスでオーバーライド
します。オーバーライドしない場合
には、Childクラスを抽象クラス
にする必要があります。
メソッドは自動的にpublic
になるので、インターフェース
の抽象メソッド
にpublic
が付いていなくても、実装するときにはpublicをつける必要があります。また、アクセス修飾子をpublicより厳しくすると
、オーバーライドの規約からコンパイルエラー
になります。
インターフェースのポリモーフィズム
インターフェース
も変数
として利用することはできます。変数
にはインターフェースを実装したクラスのオブジェクト
の参照を代入
することが可能です。
インターフェース
も抽象クラスと同様に変数
として利用すると、ポリモーフィズム
を実現
することができます。
例題(インターフェースのポリモーフィズム①)
以下は、インターフェース
のポリモーフィズム
を実現しているプログラムの書き方です。
コーディングして、実行結果を確認してみましょう。
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter10 |
インターフェース | Responsible |
package chapter10; |
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter10 |
クラス | Member |
実装 | Responsible |
package chapter10; |
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter10 |
クラス | MenberExec |
package chapter10; |
コンパイル例:> javac chapter10¥Responsible.java
> javac chapter10¥Member.java
> javac chapter10¥MenberExec.java
実行例:> java chapter10.MenberExec
Member ver1.0
ALJ会員のクラス
MenberExecクラスの「Responsible res = new Member(“ALJ”,123);」でMemberオブジェクトを作成し、Responsible型(インターフェース型)の変数「res」へ代入してます。そしてMemberクラスはResponsibleインターフェースを実装しており、「System.out.println(res.info());」と「System.out.println(res.exp());」でインターフェースで定義されているメソッドの実行結果を出力しています。「System.out.println(res.getName());」のres.getName()メソッドを実行するとコンパイルエラーになります。
例題(インターフェースのポリモーフィズム②)
以下も、インターフェース
のポリモーフィズム
を実現しているプログラムの書き方です。
(インターフェースAは、インターフェースXとインターフェースYを継承して定義している例です。)
コーディングし、実行結果を確認して下さい。
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter10 |
インターフェース名 | X |
package chapter10; |
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter10 |
インターフェース名 | Y |
package chapter10; |
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter10 |
インターフェース名 | A |
継承 | X、Y |
package chapter10; |
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter10 |
クラス | G |
実装 | A |
package chapter10; |
項目 | 名前 |
---|---|
プロジェクト | alj_study |
パッケージ | chapter10 |
クラス | InterFaceExec |
package chapter10; |
コンパイル例:> javac chapter10¥X.java
> javac chapter10¥Y.java
> javac chapter10¥A.java
> javac chapter10¥G.java
> javac chapter10¥InterFaceExec.java
実行例:> java chapter10.InterFaceExec
dispA()メソッドの実行
dispX()メソッドの実行
dispY()メソッドの実行
章のまとめ
以下の要点をしっかり理解してから次の章へ進んでください。
抽象クラス
抽象クラス
とは、クラスを設計するときに、処理内容が明確に決まってないメソッド
がある場合、概要だけを定義したメソッドを用意
し、後にそのクラスを継承
し、サブクラス内で詳細な処理を定義
する設計手法である
抽象クラスの定義
- クラスの宣言に
abstract
キーワードを指定すると抽象クラス
になる 処理定義が無く
、末尾にセミコロン( ; )
をつけたメソッドを抽象メソッド
という抽象メソッドを定義するとき
はabstract
キーワードを指定する抽象クラス
はnewでオブジェクトを作成できない
抽象メソッド
の詳細な処理内容
は、サブクラスでオーバーライド
して定義
する
抽象クラスの実装
抽象クラス
は継承(extends)
し、抽象メソッドをオーバーライド
する抽象クラス
のメソッドをオーバーライド
して具体的な処理を記述することを実装
という- @から始まる記述は、
アノテーション
といい、コンパイラに対しての命令を示す - @Overrideはコンパイラに対して、
オーバライド
していることを明示的
に示している 全ての抽象メソッド
をオーバーライド
しない場合は、サブクラスは抽象クラス
にしなければならない
抽象クラスのポリモーフィズム
抽象クラス
はインスタンス化ができないが、変数
として利用
することは可能- 抽象クラスが変数として利用されると、
ポリモーフィズム
として利用されていることとなる
インターフェース
インターフェース
とは、操作方法を統一するため
に操作のアクセスの手段のみを定義するプログラム部品のことインターフェース
はクラスでは無いので、継承関係
を考慮しなくても良い
単一継承の欠点を補う利用方法
と公開メソッドを明確にする手段
としての利用方法があるクラスが継承できるスーパークラスの数は、1つだけである(
単一継承
という)インターフェース
は、クラスでは無いので、あたかも複数のクラスを継承する
のと同じ効果を上げることができるインターフェース
は、特定の機能を実現
するために必要な定数
や抽象メソッド
の集まりであるインターフェース
で定義する定数
や抽象メソッド
は、全てpublicなメンバ
で構成される- 外部に公開するメソッドを
全てインターフェースとして定義
することで、クラスの利用者
は実装されているインターフェースを確認
すれば、クラスにどのような機能があるかを理解
できる
インターフェース定義
インターフェース
には定数
と抽象メソッド
のみ定義ができる- Java SE8からは
default
キーワードを利用すると、具象メソッドを定義することが可能 - 定数には
public static final
が自動的に付加される - メソッドには
public abstract
が自動的に付加される - インターフェースファイル名も拡張子は
.java
である extends
で他の複数のインターフェース
を拡張
できる
インターフェースの実装
implements
キーワードでインターフェース
をクラス
へ実装
できる- 一度に
複数のインターフェース
を実装
できる - クラスの
継承(extends)
と併用
できる
インターフェースのポリモーフィズム
インターフェース
は、変数
として利用することは可能(インターフェース型
)- インターフェースが変数として利用されると、
ポリモーフィズム
として利用されていることとなる