Java 抽象クラス


オブジェクト指向の概念では、すべてのオブジェクトはクラスによって記述されます。しかし逆に、すべてのクラスがオブジェクトを記述するために使われるわけではありません。クラスの中に具体的なオブジェクトを記述するための十分な情報が含まれていない場合、そのようなクラスは抽象クラスです。

抽象クラスは、オブジェクトをインスタンス化できないこと以外は、クラスの他の機能は依然として存在し、メンバー変数、メンバーメソッド、コンストラクタのアクセス方法は通常のクラスと同じです。

抽象クラスはオブジェクトをインスタンス化できないため、使用するには抽象クラスを継承する必要があります。この理由から、通常は設計段階で抽象クラスを設計するかどうかを決定します。

親クラスはサブクラス集合の共通メソッドを含みますが、親クラス自体が抽象的であるため、これらのメソッドを使用することはできません。

Java では、抽象クラスは継承関係を表します。1つのクラスは1つの抽象クラスしか継承できませんが、1つのクラスは複数のインターフェースを実装できます。


抽象クラス

Java 言語では、abstract class を使用して抽象クラスを定義します。次の例のとおりです。

Employee.java ファイルのコード:

/*ファイル名 : Employee.java*/ public abstract class Employee { private String name; private String address; private int number; public Employee(String name, String address, int number) { System.out.println("Constructing an Employee"); this.name = name; this.address = address; this.number = number; } public double computePay() { System.out.println("Inside Employee computePay"); return 0.0; } public void mailCheck() { System.out.println("Mailing a check to " + this.name + " " + this.address); } public String toString() { return name + " " + address + " " + number; } public String getName() { return name; } public String getAddress() { return address; } public void setAddress(String newAddress) { address = newAddress; } public int getNumber() { return number; } }

この Employee クラスは何も違いがないことに注意してください。このクラスは抽象クラスですが、それでも3つのメンバー変数、7つのメンバーメソッド、1つのコンストラクタを持っています。次に、以下の例を試してみると:

AbstractDemo.java ファイルのコード:

/*ファイル名 : AbstractDemo.java*/ public class AbstractDemo { public static void main(String [] args) { /*以下は許可されておらず、エラーが発生します。*/ Employee e = new Employee("George W.", "Houston, TX", 43); System.out.println("\n Call mailCheck using Employee reference--"); e.mailCheck(); } }

AbstractDemo クラスをコンパイルしようとすると、次のエラーが発生します:

Employee.java:46: Employee is abstract; cannot be instantiated
      Employee e = new Employee("George W.", "Houston, TX", 43);
                   ^
1 error

抽象クラスの継承

次の方法で Employee クラスの属性を継承できます:

Salary.java ファイルのコード:

/*ファイル名 : Salary.java*/ public class Salary extends Employee { private double salary; //Annual salary public Salary(String name, String address, int number, double salary) { super(name, address, number); setSalary(salary); } public void mailCheck() { System.out.println("Within mailCheck of Salary class "); System.out.println("Mailing check to " + getName() + " with salary " + salary); } public double getSalary() { return salary; } public void setSalary(double newSalary) { if(newSalary >= 0.0) { salary = newSalary; } } public double computePay() { System.out.println("Computing salary pay for " + getName()); return salary/52; } }

Employee クラスのオブジェクトをインスタンス化できなくても、Salary クラスのオブジェクトをインスタンス化すると、そのオブジェクトは Employee クラスから7つのメンバーメソッドを継承し、それらのメソッドを通じて3つのメンバー変数を設定または取得できます。

AbstractDemo.java ファイルのコード:

/*ファイル名 : AbstractDemo.java*/ public class AbstractDemo { public static void main(String [] args) { Salary s = new Salary("Mohd Mohtashim", "Ambehta, UP", 3, 3600.00); Employee e = new Salary("John Adams", "Boston, MA", 2, 2400.00); System.out.println("Call mailCheck using Salary reference --"); s.mailCheck(); System.out.println("\n Call mailCheck using Employee reference--"); e.mailCheck(); } }

上記のプログラムをコンパイルして実行した結果は次のとおりです:

Constructing an Employee
Constructing an Employee
Call mailCheck using  Salary reference --
Within mailCheck of Salary class
Mailing check to Mohd Mohtashim with salary 3600.0

Call mailCheck using Employee reference--
Within mailCheck of Salary class
Mailing check to John Adams with salary 2400.

抽象メソッド

このようなクラス、つまり特別なメンバーメソッドを含み、そのメソッドの具体的な実装がサブクラスによって決定されるクラスを設計したい場合、親クラスでそのメソッドを抽象メソッドとして宣言できます。

Abstract キーワードは抽象メソッドの宣言にも使用できます。抽象メソッドはメソッド名のみを含み、メソッド本体を持ちません。

抽象メソッドは定義を持たず、メソッド名の直後には波括弧ではなくセミコロンが続きます。

public abstract class Employee { private String name; private String address; private int number; public abstract double computePay(); //その他のコード }

抽象メソッドを宣言すると、次の2つの結果が生じます:

  • クラスが抽象メソッドを含む場合、そのクラスは抽象クラスでなければなりません。
  • すべてのサブクラスは親クラスの抽象メソッドをオーバーライドするか、自身を抽象クラスとして宣言する必要があります。

抽象メソッドを継承したサブクラスはそのメソッドをオーバーライドする必要があります。そうしない場合、そのサブクラスも抽象クラスとして宣言する必要があります。最終的には、いずれかのサブクラスがその抽象メソッドを実装する必要があります。そうでなければ、最初の親クラスから最終的なサブクラスまで、オブジェクトのインスタンス化に使用できません。

Salary クラスが Employee クラスを継承する場合、computePay() メソッドを実装する必要があります:

Salary.java ファイルのコード:

/*ファイル名 : Salary.java*/ public class Salary extends Employee { private double salary; // Annual salary public double computePay() { System.out.println("Computing salary pay for " + getName()); return salary/52; } //その他のコード }

抽象クラスのまとめとルール

  • 1. 抽象クラスはインスタンス化できません(初心者が犯しやすい間違いです)。インスタンス化するとエラーが発生し、コンパイルが通りません。抽象クラスの非抽象サブクラスのみがオブジェクトを作成できます。

  • 2. 抽象クラスには抽象メソッドが含まれるとは限りませんが、抽象メソッドを持つクラスは必ず抽象クラスです。

  • 3. 抽象クラス内の抽象メソッドは宣言のみで、メソッド本体を含みません。つまり、メソッドの具体的な実装、すなわちメソッドの具体的な機能を提供しません。

  • 4. コンストラクタとクラスメソッド(static で修飾されたメソッド)は抽象メソッドとして宣言できません。

  • 5. 抽象クラスのサブクラスは、抽象クラス内の抽象メソッドの具体的な実装を提供する必要があります。ただし、そのサブクラスも抽象クラスである場合は除きます。

その他の拡張