抽象クラスの利用方法
2.2 抽象クラスの利用方法
プログラムでどのように記述すれば、抽象クラスを利用できるのかその方法について説明していきます。
2.2.1 抽象クラスを定義する方法について
抽象クラスはオブジェクト化できない特殊なクラスの為、継承して利用する事が大前提になります。
まずは抽象クラスを定義する基本構文を以下に示します。
抽象クラスの定義は「abstract修飾子」を利用する事以外は、通常のクラスを定義する方法と同じです。さらに抽象クラス内では、「処理内容が定義されていないメソッドである抽象メソッド」を定義する事もできます。この抽象メソッドは任意で定義できるもので、継承されるサブクラスで強制的に機能(メソッド)を実装させたい場合に利用します。
ポイント
- 抽象クラスを定義するにはabstract修飾子を利用する。さらに処理内容を持たない抽象メソッドを定義する事ができる。
凡例:抽象クラスの継承
抽象クラスを継承する方法は通常のクラスを継承する方法「サブクラス名 extends スーパークラス名」と同じで、継承元のスーパークラスが通常のクラスから抽象クラスに変わるだけです。但し抽象メソッドが定義されていると、サブクラスでは必ずオーバーライドしてメソッドを定義しないといけません。
上記凡例で示した2つのComputer1クラスとTelevision1クラスは、前述した凡例の抽象クラス「Machinery(機械)」クラスを継承しています。Machineryクラスには抽象メソッド「show()」が定義されているので、両方のクラス内でshow()メソッドをオーバーライドしています。この抽象メソッドのオーバーライドを行わないとコンパイルエラーになるので注意が必要です。
ポイント
- 抽象クラスを継承する場合extends修飾子を利用する。抽象メソッドが定義されている場合、必ずサブクラス内でオーバーライドする必要がある。
では、次の項で抽象クラスを継承した新しいクラスを利用するプログラムを紹介します。
2.2.2 抽象クラスを継承した新しいクラスを利用するプログラム
抽象クラスを継承して新しいクラスを作成し、継承元(スーパークラス)の機能も自身のクラスの機能も正しく利用できる事を確認します。
➢ Machinery.java ※スーパークラス(抽象クラス)① ソース・フォルダー :myproj_basic/src
② パッケージ :jp.co.f1.basic.ch12
③ 名前 :Machinery
package jp.co.f1.basic.ch12; public abstract class Machinery { private int epower; // 消費電力(electric power consumption) // コンストラクタ public Machinery() { this.epower = 0; } // アクセサメソッド(共通処理) public void setEpower(int epower) { this.epower = epower; System.out.println("消費電力を" + epower + "Wに設定しました。"); } public int getEpower() { return epower; } // 抽象メソッド public abstract void show(); }
解説
このMachineryクラスは3行目のabstract修飾子でクラスを定義しているので抽象クラスになっています。
抽象クラスになっても基本的なメンバ(フィールド変数、コンストラクタ、メソッド)を宣言できるのは、通常のクラスと変わりません。機械の共通機能として消費電力を扱う為の定義を行っています。
20行目で抽象クラスとしてshow()メソッドを定義しますが、処理の内容は定義しません。間違って定義してしまうとコンパイルエラーになるので注意して下さい。この抽象メソッドは抽象クラスを継承した、サブクラスに必ず実装して欲しい機能として定義しています。
➢ Computer1.java ※抽象クラスを継承したサブクラス① ソース・フォルダー :myproj_basic/src
② パッケージ :jp.co.f1.basic.ch12
③ 名前 :Computer1
package jp.co.f1.basic.ch12; //抽象クラスのMachineryクラスを継承 public class Computer1 extends Machinery { private String os; private int memory; // コンストラクタ(引数あり) public Computer1(String os, int memory) { this.os = os; this.memory = memory; System.out.println("OS「" + os + "」メモリサイズ「" + memory + "MByte」のパソコンを作成しました。"); } // 抽象メソッドをオーバーライド public void show() { System.out.println("パソコンのOSは「" + os + "」です。"); System.out.println("メモリサイズは「" + memory + "MByte」です。"); } }
解説
4行目で抽象クラスであるMachineryクラスを継承しています。
16行目でMachineryクラスの抽象メソッドであるshow()メソッドをオーバーライドしています。
➢ Television1.java ※抽象クラスを継承したサブクラス① ソース・フォルダー :myproj_basic/src
② パッケージ :jp.co.f1.basic.ch12
③ 名前 :Television1
package jp.co.f1.basic.ch12; //抽象クラスのMachineryクラスを継承 public class Television1 extends Machinery { private int screenSize; // 画面サイズ // 引数なしのコンストラクタ public Television1() { this.screenSize = 0; System.out.println("テレビを作成しました。"); } // アクセサメソッド public void setScreenSize(int screenSize) { this.screenSize = screenSize; System.out.println("画面サイズは" + screenSize + "型にしました。"); } // 抽象メソッドをオーバーライド public void show() { System.out.println("テレビの画面サイズは" + this.screenSize + "型です。"); } }
解説
4行目で抽象クラスであるMachineryクラスを継承しています。
18行目でMachineryクラスの抽象メソッドであるshow()メソッドをオーバーライドしています。
抽象クラスであるMachineryクラスを継承したComputer1クラスとTelevision1クラスのイメージは以下のようになります。抽象メソッドを必ずオーバーライドして定義しなければならない事を除けば、通常のクラスを継承するのと変わりありません。
図 2.2.1:抽象クラスの継承
➢ UseExtendsAbstractClass.java ※mainメソッドを持つ実行クラス① ソース・フォルダー :myproj_basic/src
② パッケージ :jp.co.f1.basic.ch12
③ 名前 :UseExtendsAbstractClass
④ 作成するメソッド・スタブの選択:public static void main(String[] args) にチェックを入れる
package jp.co.f1.basic.ch12; public class UseExtendsAbstractClass { public static void main(String[] args) { // Computer1クラスをオブジェクト化 System.out.println("[Computer1オブジェクトの作成]"); Computer1 com = new Computer1("Windows7", 3072); com.setEpower(350); System.out.println("---------------------------------------"); // Television1クラスをオブジェクト化 System.out.println("[Television1オブジェクトの作成]"); Television1 tv = new Television1(); tv.setScreenSize(42); tv.setEpower(50); System.out.println("---------------------------------------"); // Computer1とTelevision1オブジェクトの情報を表示 System.out.println("■Computer1情報を表示"); com.show(); System.out.println("■Television1情報を表示"); tv.show(); } }
実行結果
解説
7行目でComputer1クラスのオブジェクト化を引数ありのコンストラクタで行っています。
8行目ではスーパークラス(抽象クラスのMachineryクラス)から継承したsetEpower()メソッドを利用して消費電力の値350を設定しています。
7、8行目の処理は実行結果を見て分かるように、正しく実行されているのが確認できます。
続いて13行目でTelevision1クラスのオブジェクトを引数なしのコンストラクタで行っています。14行目では自身のクラスのsetScreenSize()メソッドを呼び出して、画面サイズの値42を設定しています。
15行目ではスーパークラス(抽象クラスのMachineryクラス)から継承したsetEpower()メソッドを利用して消費電力の値50を設定しています。
13~15行目の処理は実行結果を見て分かるように、正しく実行されているのが確認できます。
最後に20、22行目でスーパークラス(抽象クラスのMachineryクラス)の抽象メソッドであるshow()メソッドをオーバーライドしたshow()メソッドを呼び出して各オブジェクトの情報を表示しています。
20、22行目の処理は実行結果を見て分かるように、正しく各クラスでオーバーライドしたshow()メソッドが実行されているのが確認できます。
今回のプログラムで抽象クラスを継承したサブクラスを扱いました。抽象クラスに抽象メソッドが定義されていると必ずサブクラスでオーバーライドしなければなりません。
図 2.2.2: 抽象クラスで宣言した抽象メソッドのオーバーライド