継承には
①スーパークラスを元にフィールドやメソッドをサブクラスに引き継がせて機能追加をする方法
②サブクラスが共通して持っているフィールドやメンバ変数、メソッドを元にスーパークラスに共通点をまとめて他のサブクラスに継承させる方法
がある。
②の様な方法で継承させる際に共通のメソッドの定義のみをスーパークラスに継承させたメソッド( System.out.printlnなどの実装内容を持たないメソッド)を抽象メソッド、抽象メソッドを一つでも含むクラスは抽象クラスと呼ぶ。
また、異なる実装内容を持つオブジェクトを、同一のメソッドで扱うことができることポリモフィズムをと呼ぶ。
ポリモフィズムは、・多様性・多態性・多相性ともいう。
抽象クラスと抽象メソッド
・メソッドの定義だけを書いて実装内容(処理の中身)を持たないメソッドを抽象メソッドと呼び、修飾子にabstractをつけて定義する。
・クラスの中に一つでも抽象メソッドが含まれているクラスを抽象クラスと呼び修飾子にabstractをつけて定義する。
アクセス修飾子 abstract class 抽象クラス名{
// ↓抽象メソッド
アクセス修飾子 abstract 戻り値の型 抽象メソッド名();
}
//System.out.printlnなどの実装内容や処理は書かない
✳︎抽象メソッドには、private/static/final修飾子を付けることはできない。
✳︎アクセス修飾子と戻り値は必要な場合に記述する。
抽象クラスを利用するときは抽象クラスを継承したサブクラスを定義し、抽象メソッドをオーバーライドする。
この書き方(ポリモフィズム)で書くメリットは新たにクラスを追加する時に
・メソッドの作成漏れを防ぎ、メソッド名を統一出来るのでプログラムが見やすくなる。
・呼び出す側のクラスの記述を修正しなくて済む。
などがありプログラムの機能を拡張しやすくなる。
抽象クラスと抽象メソッドのポイント
・抽象クラスは継承元(スーパークラス)となることが前提のクラス
・抽象メソッドは継承先(サブクラス)でオーバーライドされることで処理内容が確定する。
(「オーバーライドされることで処理内容が確定する」=「処理内容が確定していないクラス」なのでnewによるインスタンス化ができない)
例文
public class StuSample6{
public static void main(String[] args){
TandF taf = new TandF("陸上部");
Football fb = new Football("サッカー部");
Student6 stu1 = new Student6("菅原",taf);
stu1.display();
stu1.practice();
Student6 stu2 = new Student6("田仲",fb);
stu2.display();
stu2.practice();
}
}
public abstract class Club{
private String name; // 部活名
public Club(String name){
this.name = name;
}
public void display(){
System.out.println("部活動:" + name);
}
public abstract void practice();
}
public class Student6{
private String name; // 名前
private Club club; // Clubオブジェクト
public Student6(String name, Club club){
this.name = name;
this.club = club;
}
public void display(){
System.out.println("名前:" + name);
club.display();
}
public void practice(){
club.practice();
System.out.println("------");
}
}
public class Football extends Club{
public Football(String name){
super(name);
}
public void practice(){
System.out.println("ドリブル");
System.out.println("シュート練習");
System.out.println("ミニゲーム");
}
}
public class TandF extends Club{
public TandF(String name){
super(name);
}
public void practice(){
System.out.println("ウォームアップ");
System.out.println("インターバル");
System.out.println("筋トレ");
}
}
名前:菅原
部活動:陸上部
ウォームアップ
インターバル
筋トレ
------
名前:田仲
部活動:サッカー部
ドリブル
シュート練習
ミニゲーム
------
Clubクラスでは10行目で抽象メソッドであるpracticeメソッドを定義している。抽象メソッドを含んでいるのでクラス定義は”public abstract class Club”となる。
Clubクラスはサブクラスで継承して抽象メソッドを上書きして中身を実装する必要がある。この継承しているクラスがFootballクラスとTandFクラスでpracticeメソッドはFootballクラスとTandFクラスで定義されている。
FootballクラスとTandFクラスの両方とも2行目でコンストラクタを定義し、5行目でClubクラスの抽象メソッドであるpracticeメソッドの処理の中身を実装している。
Student6クラスでFootballクラスとTandFクラスの情報をまとめたClubクラスの情報を扱っている。
2行目でメンバ変数、3行目でClubオブジェクトを持たせて、5行目のコンストラクタで受け取っている。
9、13行目のメソッドでClubクラス側のdisplayメソッドとpracticeメソッドを呼び出している。
StuSampleクラスでは2、3行目で2つのオブジェクトを作ってコンスタントにそれぞれ”陸上部”、”サッカー部”という値を格納し、コンストラクタを呼び出している。
6行目でStudent6 stu1 = new Student6("菅原",taf);とコンストラクタを呼び出しているがtafには”陸上部”という値が格納されているのでStudent6クラスの5行目のコンストラクタのString nameに”菅原”、Club clubに”陸上部”の値が渡される。
なので7行目のdisplayメソッドで”名前:菅原””部活動:陸上部”と出力される
10行目も同様の処理。
参考記事