第10章 抽象クラスとインターフェース

はじめに

この章では、インスタンス化を行うことができる具象クラス、抽象メソッドを定義することができる抽象クラス、クラスにおいて仕様の役割を持つインターフェースについて、それぞれの特徴と定義の方法を学習します。

目次

  • 抽象クラス
  • 抽象クラスの定義
  • 抽象クラスの実装
  • 抽象クラスのポリモーフィズム
  • インターフェース
  • インターフェースの定義
  • インターフェースの実装
  • インターフェースのポリモーフィズム
  • 章のまとめ

目標

抽象クラスとインターフェースについて理解すること。

抽象クラス

抽象クラスとは、他のクラスにより、継承されることを前提に定義されたクラスです。そのため、抽象クラスインスタンス化することができません。

抽象クラスは、クラスの設計をおこなう際に、まだ処理内容が明確に決まってない場合に、概要だけを抽象メソッドとして定義し、そのクラスを継承したサブクラス内詳細な処理を定義する設計手法です。

抽象クラスの定義

抽象クラスを定義するためには、クラスの宣言に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;

/**
* 挨拶クラス(抽象クラス)
* @version 1.0
* @author Yamamoto
*/
public abstract class Greeting {

/**
* 言語設定メソッド(抽象メソッド)
* @param 無し
* @return 言語名
*/
public abstract String language();

/**
* 挨拶文生成メソッド(抽象メソッド)
* @param 無し
* @return 挨拶文章
*/
public abstract String message();
}

抽象クラスを作成するときはabstractキーワードを使用します。またメソッドに関しても抽象メソッドという形式で書きます。

尚、abstractキーワードはアクセス修飾子の前に書いても良いです。

package chapter10;

/**
* 挨拶クラス(抽象クラス)
* @version 1.0
* @author Yamamoto
*/
public abstract class Greeting {

/**
* 言語設定メソッド(抽象メソッド)
* @param 無し
* @return 言語名
*/
abstract public String language();

/**
* 挨拶文生成メソッド(抽象メソッド)
* @param 無し
* @return 挨拶文章
*/
public abstract String message();

}

抽象クラスを継承したサブクラスでは、必ずabstractキーワードが付与されているメソッドをオーバーライド(実装)します。

項目 名前
プロジェクト alj_study
パッケージ chapter10
クラス名 JapaneseGreeting
継承 Greeting
package chapter10;

/**
* 日本語挨拶クラス
* @version 1.0
* @author Yamamoto
*/
public class JapaneseGreeting extends Greeting {

@Override
public String language(){
return "Japanese";
}

@Override
public String message(){
return "こんにちは";
}
}

サブクラスで抽象メソッドオーバーライド(実装)しないとコンパイルエラーになります。

項目 名前
プロジェクト alj_study
パッケージ chapter10
クラス名 GreetingExec
package chapter10;
/**
* 実行する為のクラス
* @version 1.0
* @author Yamamoto
*/
public class GreetingExec {

/**
* main()メソッド
*/
public static void main(String[] args) {
JapaneseGreeting jg = new JapaneseGreeting();
System.out.println("言語:" + jg.language);
System.out.println("挨拶:" + jg.message);
}

}

コンパイル例:

> 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;
/**
* Transportクラス
* @version 1.0
* @author Yamamoto
*/
public abstract class Transport {

/**
* 名前を保持
*/
protected int speed = 0;

/**
* runメソッド(抽象メソッド)
* @param 無し
* @return 無し
*/
public abstract void run();

/**
* stopメソッド(抽象メソッド)
* @param 無し
* @return 無し
*/
public void stop(){
speed = 0;
System.out.println("止まります。");
}

}
項目 名前
プロジェクト alj_study
パッケージ chapter10
クラス名 Car
継承 Transport
package chapter10;
/**
* Carクラス
* @version 1.0
* @author Yamamoto
*/
public class Car extends Transport {

@Override
public void run() {
speed = 100;
System.out.println("Car:スピード : " + speed );
}

}
項目 名前
プロジェクト alj_study
パッケージ chapter10
クラス名 Bass
継承 Transport
package chapter10;
/**
* Bassクラス
* @version 1.0
* @author Yamamoto
*/
public class Bass extends Transport {

@Override
public void run() {
speed = 50;
System.out.println("Bass:スピード : " + speed );
}

}
項目 名前
プロジェクト alj_study
パッケージ chapter10
クラス名 TransportExec
package chapter10;
/**
* 実行する為のクラス
* @version 1.0
* @author Yamamoto
*/
public class TransportExec {

/**
* main()メソッド
*/
public static void main(String[] args) {

//Carオブジェクトを生成し、Carクラス型の変数cへ代入
Car c = new Car();
//Carオブジェクトのrun()メソッドを実行
c.run();
//Carオブジェクトのstop()メソッドを実行
c.stop();

//Bassオブジェクトを生成し、Bassクラス型の変数bへ代入
Bass b = new Bass();
//Bassオブジェクトのrun()メソッドを実行
b.run();
//Bassオブジェクトのstop()メソッドを実行
b.stop();

}
}

コンパイル例:

> 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;
/**
* 実行するためのクラス
* @version 1.0
* @author Yamamoto
*/
public class TransportExec {
/**
* main()メソッド
*/
public static void main(String[] args) {

//-----ここから(修正)-----
//Carオブジェクトを生成し、Transportクラス型の変数tcへ代入
Transport tc = new Car();
//Transportクラス型の変数tcからCarオブジェクトのrun()メソッドを実行
tc.run();
//Transportクラス型の変数tcからCarオブジェクトのstop()メソッドを実行
tc.stop();

//Bassオブジェクトを生成し、//Transportクラス型の変数tbへ代入
Bass tb = new Bass();
//Transportクラス型の変数tbからBassオブジェクトのrun()メソッドを実行
tb.run();
//Transportクラス型の変数tbからBassオブジェクトのstop()メソッドを実行
tb.stop();
//-----ここまで(修正)-----

}
}

コンパイル例:

> 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;
/**
* Withdrawインターフェース
* @version 1.0
* @author Yamamoto
*/
public interface Withdraw{

//定数MAX(300000)を定義
public static final MAX = 300000;

//toWithDrawメソッドを定義
public abstract void toWithDraw(int money);

}

上記のように、インターフェースには定数抽象メソッドだけを定義します。

※Java SE8からはdefaultキーワードを利用すると、具象メソッドを定義することが可能になっています。

尚、以下のように定義することも可能です。

package chapter10;
/**
* Withdrawインターフェース
* @version 1.0
* @author Yamamoto
*/
public interface Withdraw{

//定数MAX(300000)を定義
int MAX = 300000;

//toWithDrawメソッドを定義
void toWithDraw(int money);

}

上記のインターフェースをコンパイルすると以下のようになります。

package chapter10;
/**
* Withdrawインターフェース
* @version 1.0
* @author Yamamoto
*/
public abstract interface Withdraw{ //abstractが付加される

//定数MAX(300000)を定義
public static final MAX = 300000; //public static final が付加される

//toWithDrawメソッドを定義
public abstract void toWithDraw(int money); //public abstract が付加される

}

上記をコンパイルすると、自動的publicアクセスとみなされるので、定義の中でpublicをつける必要はありません。また、staticfinalabstractも、コンパイラが自動的に付加してくれるので、定数メソッドプログラマ自身付加する必要はありません(付けても間違えではないです。)

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;

public interface X {
void dispX();
}
項目 名前
プロジェクト alj_study
パッケージ chapter10
インターフェース名 Y
package chapter10;

public interface Y {
void dispY();
}
項目 名前
プロジェクト alj_study
パッケージ chapter10
インターフェース名 A
継承 X、Y
package chapter10;

public interface A extends X, Y {
void dispA();
}

※インターフェースは多重継承することが可能です。

尚、クラスへ実装する場合は、全てのインターフェースで定義されている抽象メソッドをオーバーライドしなければなりません。(次の項目の「インターフェースの実装」を参考にして下さい)

インターフェースの実装

インターフェースを実装するときはimplementsキーワードを利用します。そしてインターフェースで定義しているメソッドをオーバーライドします。正しく利用しないとコンパイルエラーになります。

  • implementsキーワードを使ってインターフェースを実装する
  • 一度に複数のインターフェース実装できる
  • クラスの継承(extends)併用できる

例題(インターフェースの実装)

以下はインターフェースの実装する例です。
コーディングし、実行結果を確認してみましょう。

項目 名前
プロジェクト alj_study
パッケージ chapter10
インターフェース Tools
package chapter10;
/**
* Toolsインターフェース
* @version 1.0
* @author Yamamoto
*/
interface Tools {

/**
* MAX定数(1000)を保持
*/
int MAX = 1000; //定数MAX(1000)

/**
* 表示
* @param 無し
* @return 無し
*/
void disp(); //dispメソッド
}
項目 名前
プロジェクト alj_study
パッケージ chapter10
インターフェース Var
package chapter10;
/**
* Varインターフェース
* @version 1.0
* @author Yamamoto
*/
interface Var {

/**
* 定数SUM(500)を保持
*/
int SUM = 500; //定数SUM(500)
}
項目 名前
プロジェクト alj_study
パッケージ chapter10
クラス Parent
package chapter10;
/**
* Parentクラス
* @version 1.0
* @author Yamamoto
*/
class Parent {

/**
* 変数nを保持
*/
int n;
}
項目 名前
プロジェクト alj_study
パッケージ chapter10
クラス Child
継承 Parent
実装 Tools , Var
package chapter10;
/**
* Childクラス
* @version 1.0
* @author Yamamoto
*/
class Child extends Parent implements Tools , Var {

@Override
public void disp(){
System.out.println(n);
}

}
項目 名前
プロジェクト alj_study
パッケージ chapter10
クラス ChildExec
package chapter10;
/**
* 実行するためのクラス
* @version 1.0
* @author Yamamoto
*/
public class ChildExec {

/**
* main()メソッド
*/
public static void main( String[] args ){

Child c = new Child();
c.n = 100;
System.out.println(c.SUM);
c.disp();

}

}

コンパイル例:

> 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;
/**
* Responsibleインターフェース
* @version 1.0
* @author Yamamoto
*/
public abstract interface Responsible{

/**
* クラス名、バージョンを生成
* @param 無し
* @return String クラス名とバージョン
*/
public abstract String info();

/**
* クラスの説明文を作成
* @param 無し
* @return String 説明文
*/
public abstract String exp();
}
項目 名前
プロジェクト alj_study
パッケージ chapter10
クラス Member
実装 Responsible
package chapter10;
/**
* Memberクラス
* @version 1.0
* @author Yamamoto
*/
public class Member implements Responsible {

/**
* 名前を保持
*/
private String name;

/**
* ID番号を保持
*/
private int id;

/**
* コンストラクタ
*/
Member(String name,int id){
this.name = name;
this.id = id;
}

/**
* アクセサメソッド
* @return name 名前
*/
public String getName() {
return name;
}

/**
* アクセサメソッド
* @param name 名前
*/
public void setName(String name) {
this.name = name;
}

/**
* アクセサメソッド
* @return id ID番号
*/
public int getId() {
return id;
}

/**
* アクセサメソッド
* @param id ID番号
*/
public void setId(int id) {
this.id = id;
}

/**
* displayメソッド
* @param 無し
* @return 無し
*/
public void display(){
System.out.println(this.name);
System.out.println(this.id);
}

@Override
public String info() {
return "Member ver1.0";
}

@Override
public String exp() {
return "ALJ会員のクラス";
}

}
項目 名前
プロジェクト alj_study
パッケージ chapter10
クラス MenberExec
package chapter10;
/**
* 実行するためのクラス
* @version 1.0
* @author Yamamoto
*/
public class MenberExec {

/**
* main()メソッド
*/
public static void main(String[] args) {

Responsible res = new Member("ALJ",123);
System.out.println(res.info());
System.out.println(res.exp());
//System.out.println(res.getName());

}
}

コンパイル例:

> 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;

public interface X {
void dispX();
}
項目 名前
プロジェクト alj_study
パッケージ chapter10
インターフェース名 Y
package chapter10;

public interface Y {
void dispY();
}
項目 名前
プロジェクト alj_study
パッケージ chapter10
インターフェース名 A
継承 X、Y
package chapter10;

public interface A extends X, Y {
void dispA();
}
項目 名前
プロジェクト alj_study
パッケージ chapter10
クラス G
実装 A
package chapter10;
/**
* 実行するためのクラス
* @version 1.0
* @author Yamamoto
*/
public class G implements A {
@Override
public void dispX() {
System.out.println("")
}
@Override
public void dispY() {
//処理を定義する
}
@Override
public void dispA() {
//処理を定義する
}
}
項目 名前
プロジェクト alj_study
パッケージ chapter10
クラス InterFaceExec
package chapter10;
/**
* 実行するためのクラス
* @version 1.0
* @author Yamamoto
*/
public class InterFaceExec {

/**
* main()メソッド
*/
public static void main(String[] args) {
A a = new G();
a.dispA();
a.dispX();
a.dispY();
}
}

コンパイル例:

> 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)併用できる

インターフェースのポリモーフィズム

  • インターフェースは、変数として利用することは可能(インターフェース型
  • インターフェースが変数として利用されると、ポリモーフィズムとして利用されていることとなる