Java抽象化完全ガイド: 抽象クラス・抽象メソッドで実装を隠蔽し設計を簡潔に
辞書によれば、抽象化とは「出来事ではなくアイデアを扱う性質」です。例えばEメールを考えると、Eメールを送信した直後に何が起こるか、Eメールサーバーが使用するプロトコルなどの複雑な詳細はユーザーから隠蔽されています。したがって、Eメールを送信するには内容を入力し、受信者のアドレスを指定し、送信をクリックするだけで済みます。
同様にオブジェクト指向プログラミングにおいて、抽象化とは実装の詳細をユーザーから隠蔽し、機能のみをユーザーに提供するプロセスです。言い換えれば、ユーザーはオブジェクトが何をするかを知っていて、どのようにするかを知る必要はありません。
Javaでは、抽象クラスとインターフェースを使用して抽象化を実現します。
抽象クラス
宣言にabstractキーワードを含むクラスを抽象クラスと呼びます。
- 抽象クラスは抽象メソッド(本体のないメソッド:
public void get();)を含む場合と含まない場合がある。 - しかし、クラスが少なくとも1つの抽象メソッドを持つ場合、そのクラスは必ずabstractと宣言しなければならない。
- クラスがabstractと宣言されている場合、インスタンス化できない。
- 抽象クラスを使用するには、別のクラスから継承し、その中の抽象メソッドに実装を提供する必要がある。
- 抽象クラスを継承する場合、その中のすべての抽象メソッドに実装を提供しなければならない。
例: 抽象クラスの作成
抽象クラスを作成するには、クラス宣言でclassキーワードの前にabstractキーワードを置きます。
/* File name : 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クラスはJavaの通常のクラスと同じです。クラスはabstractになりましたが、依然として3つのフィールド、7つのメソッド、1つのコンストラクタを持っています。
以下のようにEmployeeクラスをインスタンス化しようとするとどうなるか。
/* File name : 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();
}
}
上記クラスをコンパイルすると以下のエラーが発生します。
Employee.java:46: Employee is abstract; cannot be instantiated
Employee e = new Employee("George W.", "Houston, TX", 43);
^
1 error
抽象クラスの継承
Employeeクラスのプロパティは、具象クラスと同様に以下のように継承できます。
例: SalaryクラスでEmployeeを継承
/* File name : Salary.java */
public class Salary extends Employee {
private double 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クラスの3つのフィールドと7つのメソッドすべてにアクセスできます。
/* File name : 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.0
抽象メソッド
クラスに特定のメソッドを含めたいが、そのメソッドの実際の実装を子クラスに決定させたい場合、そのメソッドを親クラスで抽象として宣言できます。
- abstractキーワードを使用してメソッドを抽象として宣言。
- メソッド宣言でメソッド名の前にabstractキーワードを配置。
- 抽象メソッドはメソッドシグニチャを含むが、メソッドボディを含まない。
- 波括弧の代わりに、抽象メソッドの末尾にはセミコロン(;)を置く。
例: 抽象メソッド
public abstract class Employee {
private String name;
private String address;
private int number;
public abstract double computePay(); // 抽象メソッド
// クラス定義の残り
}
メソッドを抽象として宣言すると2つの結果が生じます。
- それを含むクラスはabstractと宣言しなければならない。
- 現在のクラスを継承するクラスは、抽象メソッドをオーバーライドするか、自身をabstractと宣言しなければならない。
注意 - 最終的に、子孫クラスが抽象メソッドを実装しなければなりません。そうでなければ、インスタンス化できない抽象クラスの階層ができてしまいます。
SalaryクラスがEmployeeクラスを継承する場合、以下のようにcomputePay()メソッドを実装する必要があります。
/* File name : Salary.java */
public class Salary extends Employee {
private double salary; // 年俸
public double computePay() {
System.out.println("Computing salary pay for " + getName());
return salary / 52;
}
// クラス定義の残り
}
Java
- Javaのfinalキーワード完全解説:変数、メソッド、クラスでの活用法
- Java instanceof演算子完全ガイド:基本から継承・インターフェースまで
- Java抽象クラスとメソッド:包括的ガイド
- Java Staticネストクラスの理解:用法、違い、実例
- Java無名インナークラス完全ガイド:定義、構文、実践例
- Javaシングルトンパターン完全解説:安全な実装と活用法
- Javaリフレクション完全ガイド:実行時のクラス・メソッド・フィールド検査
- Java ObjectOutputStream完全ガイド:シリアル化、メソッド、実践例
- Javaジェネリクス完全ガイド:再利用可能で型安全なコードの構築
- Javaファイル操作のマスター:java.ioによる作成・読み取り・書き込み・削除
- Java インターフェース vs 抽象クラス:適切な抽象化の選び方