Javaのabstract(抽象クラス)って何?メリットをまとめてみた
18/12/16 13:32:22 19/05/05 16:49:16
Javaはオブジェクト指向をはじめ、いくつかの特殊概念が登場します。初めてのプログラミング言語としてJavaを選択する人は多いですが、概念がよくわからなくて混乱することは多いでしょう。
みんなが通る道なので、混乱したりよくわからないまま実装したりするのも勉強のうちと言えます。そして、abstract(抽象クラス)も初心者が混乱しがちな概念の一つでしょう。抽象クラスの目的をざっくり言うと、「設計図のベースとなる設計図」のようなイメージです。
クラスが設計図、クラスを元にインスタンスを生成する、といったことはすでに学習済みかと思います。原則はこの認識で良いのですがなかには例外もあり、それが抽象クラスです。
抽象クラスは直接インスタンスを作ることができず、言い換えると設計図であるにも関わらず実際に処理するための実態ができないのです。なぜこのようなクラスが存在するのか、どのようなメリットがあるのか、ということを解説していきます。
abstract(抽象クラス)のメリット
本来抽象クラスの概要やサンプルコードから紹介するところですが、おそらくそれだといまいち腑に落ちないまま学習を進めることになります。なぜなら、「なぜ抽象クラスが存在するのか」という目的が意外とわかりにくいからです。
実際Javaである程度開発経験があるにも関わらず、抽象クラスの存在意義がいまいちよくわからないまま開発している人も多いかと思います。そこで、最初に抽象クラスのメリットについて紹介します。
目的やメリットを理解したうえで実例を見た方がおそらく腑に落ちるでしょう。抽象クラスのメリットは、「サブクラスのロジックを指定して引き継げる」ということです。これにより、サブクラスという設計書で定義する内容が明確になります。
一例として、たとえば「乗り物クラス」という抽象クラスがあったとします。乗り物は範囲が広く抽象的なので、これをそのままインスタンス化すると変なシステムになるでしょう。
そこで、乗り物クラスを抽象クラスとして定義し、サブクラスとして「自転車クラス」「自動車クラス」「バイククラス」といったクラスを定義します。ここで、それならわざわざ抽象クラスを定義せずに直接各乗り物のクラスを定義すれば良いだけでは?という疑問が出てくるかもしれません。
もちろんそれでもまったく問題ありません。しかし、それだと各乗り物ごとに定義するメソッドがばらばらになったり、結果的に統一感がなくなる、実装に漏れが生じてバグにつながる、といったことが起こりえます。
そこであらかじめ乗り物クラスとして抽象クラスを作り、それをサブクラスで引き継ぐ形にすれば、特にメソッドとして定義するものが明確になるのです。抽象クラスを引き継いだサブクラスを作成する場合、抽象クラスに含まれているメソッドをすべて引き継いで定義する必要があります。
このことを指して、抽象クラスのメリットを「多相性」「構造の規定」と言ったりします。要するに、抽象クラスをサブクラスにいろいろな形で引き継げるが、大枠のメソッドは決まっているため統一感は保たれる、といったイメージでしょう。
最近は抽象クラスを使わなくても別の方法でクラスのルール化ができるのでabstractの出番は減っているのですが、昔は特に複数人でシステム開発を行う際はabstractにする部分の規定などもよくありました。
ちなみに上の乗り物クラスのメソッドの例をざっくり挙げておくと、「タイヤメソッド」「フレームメソッド」「スピードメソッド」「ハンドルメソッド」「動力メソッド」などが挙げられます。
どの乗り物にもこのようなメソッドが適用でき、また定義しておく必要があります。抽象クラスで上記のメソッドを設定しておけば、各サブクラスで再定義できます。
abstract(抽象クラス)の使い方
次に実際に抽象クラスの実装例を紹介しますが、上で説明した抽象クラスの目的、メリットを念頭に置いたうえで見ていってください。
そうすることによって、目的やメリットが理解できないままなんとなく書き方だけ覚える、よくわからないまなんとなく実装している、といったことがなくなるでしょう。
まず抽象クラスの構文は以下です。
abstract class 抽象クラス名 {
abstract 戻り値の型名 メソッド名(引数);
}
class サブクラス名 extends 抽象クラス名 {
戻り値の型名 メソッド名(引数) {
処理内容;
}
}
abstract classとして抽象クラス名を定義し、そのなかにabstractメソッドを作成します。抽象クラスでは、メソッドも各サブクラスに引き継ぐ必要があるため、具体的な定義はしないことが多いです。具体的なサンプルコードは以下です。
abstract class AbstractClass {
abstract void abstractMethod(int num, String str);
void nonAbstractMethod() {
System.out.println("非抽象メソッドより出力");
}
}
public class Main extends AbstractClass {
public static void main(String[] args) {
Main main = new Main();
main.abstractMethod(1, "HAPPY");
}
public void abstractMethod(int num, String str) {
System.out.println("引数int num = " + num + " / 引数String str = "+ str);
}
}
上記のソースコードを実行すると、以下のようにコンソール出力されます。
引数int num = 1 / 引数String str = HAPPY
abstractクラスにabstractメソッドを実装し、それをメインクラスで引き継ぎました。また、コンストラクタを使用する方法もあります。
// スーパークラス
abstract class AbstractClass {
public AbstractClass(int num, String str) {
System.out.println("引数int num = " + num + " / 引数String str = "+ str);
}
abstract void abstractMethod(int num, String str);
void nonAbstractMethod() {
System.out.println("非抽象メソッドより出力");
}
}
// サブクラス
class SubClass extends AbstractClass {
// サブクラスからスーパークラスのコンストラクタを呼び出し
public SubClass(int num, String str) {
super(num, str);
}
public void abstractMethod(int num, String str) {
System.out.println("引数int num = " + num + " / 引数String str = "+ str);
}
}
public class Main {
public static void main(String[] args) {
SubClass sc = new SubClass(1, "HAPPY");
}
}
上記のソースコードを実行すると、以下のようにコンソール出力されます。
引数int num = 1 / 引数String str = HAPPY
サブクラス内でsuperを使って継承しています。superを使用しても同じことができるとわかりました。実際の開発でabstractをどの程度使用するかはまちまちですが、Javaにおいて重要な基本概念の一つです。
自分自身があまり使用しなくても人のソースコードを読んでいて目にすることは多いかと思うので、なぜ使用しているのか、全体構造がどのようになっているのか、といった点は把握しておいた方が良いでしょう。
Javaのフリーランス案件をチェック
人気記事