2019/02/06
前回まで継承について説明してきました。今回は継承と関係の深いabstractについて説明します。
継承が分かっていないとabstractは何のこっちゃ分からないと思うので、継承何それ?な人は継承って何?から読み直すようにして下さい。
sponsored link
abstractなメソッド
abstractというのは、メソッドの修飾子として使われます。
例えばメソッドを定義する時にvoidを付けることで、「このメソッドは戻り値を返さないメソッドです」ということを指定できるのと同じように、メソッドを定義する時にabstractを付けることで、「このメソッドはabstractなメソッドですよ。」と指定するわけです。
例)abstractでvoidなメソッドを定義しています↓
abstract void method();
では、abstractなメソッドというのは、どういうメソッドなのか?
それは処理内容がまだ定義されていないメソッドです。
肝心の処理内容はまだ決めていません。っていう状態のメソッドを定義したい時に使うのがabstractなんです。
先程のabstractメソッドの定義部分をよく見て下さい。↓
abstract void method();
メソッドを定義しているにも関わらず処理内容を定義する為の{ }がなく、;(セミコロン)で終わっているのが分かると思います。
abstractを付けてこのようなちょっと変わった書き方をすることで、処理内容が未定義のメソッドを定義することができるわけです。
じゃあ、その処理内容が決まっていないメソッドを使う(呼ぶ)とどうなるの?と心配になりますが、abstractメソッドは実はそのままでは使うことはできません。
abstractメソッドは継承、およびオーバーライドされることが大前提のメソッドなんです。
abstractなクラス
abstractの具体的な使い方や、その意味を理解するために、例としてHumanクラスを作ってみます。
Human.java
public class Human { void eat(){ System.out.println("ご飯を食べました"); } }
eatメソッドをメンバとして持つHumanクラスを書いてみました。このHumanクラスをインスタンス化して、食べさせると以下のようなコードになります。
Main.java
public class Main { public static void main(String[] args) { Human human = new Human(); human.eat(); } }
実行結果↓
このHumanクラスにabstractなメソッドを追加してみます。
Human.java
public class Human {
void eat(){
System.out.println("ご飯を食べました");
}
abstract void work();
}
これでHumanクラスはabstractなメソッド(work)を持つクラスになりました。
abstractなメソッドをメンバーとして持つクラスは、クラス自体にもabstractを付ける必要があります。
Human.java
public abstract class Human {
void eat(){
System.out.println("ご飯を食べました");
}
abstract void work();
}
※abstractなメンバーを持っているのに、classの宣言部分にabstractを付けずにいるとコンパイルエラーになります。
さて、これでHumanクラスはabstractなクラスになりました。
さあ、このHumanクラスをインスタンス化してみましょ・・とは出来ません。
abstractなクラスはインスタンス化することは出来ません。そりゃそうです。内容が未定義のメソッドというわけの分からんものがある状態でインスタンス化なんてできるはずがありません。
abstractなクラスというのは継承元(親クラス)として使う為に存在するんです。ちょっと言ってることが分からないかも知れませんが、だんだん分かってくるので、実際にHumanクラスを継承したProgrammerクラスを書いてみましょう。
Programmer.java
public class Programmer extends Human {
}
eclipse等のIDEを使って実際コードを書くと、abstractなクラスを継承した時点で、クラス名Programmerの部分に赤線が引かれコンパイルエラーになります。その赤線部分をクリックするとそのエラーを回避するための2つの方法が提示されます。
Add unimplemented methods(未定義のメソッドを追加する)をクリックすることで、親クラス(Humanクラス)ではまだ内容が未定義だったworkメソッドが、Programmerクラスのメンバーメソッドとして自動的に挿入されます。
Programmer.java
public class Programmer extends Human {
@Override
void work() {
// TODO Auto-generated method stub
}
}
↑こんな風にworkメソッドの中身を定義する為のコードが自動的に挿入されると思うので、定義部分を書いてしまいましょう。
Programmer.java
public class Programmer extends Human {
@Override
void work() {
System.out.println("プログラミングをしました");
}
}
※コメント部分は消しています。
さて、これで仕事をするProgrammerクラスが出来ました。実際にインスタンス化して仕事させてみましょう。
Main.java
public class Main { public static void main(String[] args) { Programmer programmer = new Programmer(); programmer.eat(); programmer.work(); } }
実行結果↓
ちゃんと仕事していますね。
抽象クラスと抽象メソッド
・・・で?
・・・何をそんなに回りくどいことをしてるの??
と思う気持ちも分かりますが、もう少し辛抱して読み進めて下さい。
この一連のabstractによって何をしたのかと言うと、「人間ならば何でも良いから仕事をするんだぞ!」というルールを作ったわけです。
上記の例ではProgrammerですが、例えばDoctorクラスを書くなら、以下のように書くことができます。
Doctor.java
public class Doctor extends Human {
@Override
void work() {
System.out.println("患者を診ました");
}
}
同様に、Teacherクラスなら以下のように書けます。
Teacher.java
public class Teacher extends Human {
@Override
void work() {
System.out.println("生徒に勉強を教えました");
}
}
これらのクラスはHumanクラスを継承しているので、人間(Humanオブジェクト)です。もう継承の本質を理解していますよね?
Child is Superです。
プログラマーも医者も先生も、皆、人間です。人間である以上、働かねばならないんです。
つまり、abstractという仕組みを使って、「Humanオブジェクトである以上はworkメソッドを持つ」という約束事を作ったわけです。
abstractなクラスのことを抽象クラスと表現したりします。抽象クラスは自身からインスタンスを作る為に存在するのではなく、親クラスとして子クラスを生む為だけに存在します。
実際にインスタンスを作るのは、抽象クラスを継承した子クラスが担います(上記の例で言うProgrammerクラス、Doctorクラス、Teacherクラス)。
※通常、継承の矢印は子から親に向けて書きますが、理解しやすいようにあえて逆に書いてますのでご注意を。
Humanオブジェクトである以上はworkメソッドを実装するべきなのですが、その実行内容(お仕事内容)に関してはプログラマーなのか医者なのか先生なのかによって様々な違いがあるので、Humanクラスでその仕事内容まで定義することはできません。
そこで、workメソッドをabstractなメソッド(抽象メソッド)にすることによって、「中身はそれぞれで定義したらいいけど、人間である以上はworkメソッドが呼ばれたら働けるようにしておきなさいよ。」という状態を強制することができるわけです。
抽象クラスは、いわばクラス設計の雛形として使う為に書くわけです。人間とはこうあるべきだと。
何の為のabstract?
で、結局、abstractって何の役に立つの?
と感じる人もいると居ると思います。その感覚はある意味で正しいと思います。
別にabstractなんて使わなくても、単にHumanクラスを継承するクラスには必ずworkメソッドを書けばいいだけの話ですから。
以下はabstractを使わずにProgrammerクラスにworkメソッドを追加しているだけですが、動作は全く同じです。
Human.java
public class Human { void eat(){ System.out.println("ご飯を食べました"); } }
Programmer.java
public class Programmer extends Human {
@Override
void work() {
System.out.println("プログラミングをしました");
}
}
Main.java
public class Main { public static void main(String[] args) { Programmer programmer = new Programmer(); programmer.eat(); programmer.work(); } }
実行結果↓
このように、abstractが無くても動作的には何の問題もありません。むしろこの場合はHumanクラスをインスタンス化することも可能です(出来たほうが良いかどうかはさて置き)。
では、なぜabstractを使うのかと言うと、ただ決められたクラス設計を正確に実現する為です。
「Humanクラスを継承するクラスには必ずworkメソッドを実装せよ」と紙に書いて貼っておくのではなく、Humanクラスを継承するクラスにはworkメソッドがないとコンパイルが通らないという状態を作る為にabstractを使うんです。そうすることによって、設計された決まり事をより正確に実現することができるわけです。
賢明な読者様ならお気づきだと思いますが、あくまで重要なのはクラス設計です。abstractはその決められたクラス設計を正確に漏れなくコーディングする為のツールみたいなものであって、もしクラス設計自体に問題があれば何の役にも立ちませんし、むしろ邪魔になるかも知れません。
なので、自分でabstractを使いこなしてコーディングするというのは、より良いクラス設計が出来ないと無理なので、ちょっとハードルは高めです。
初心者としては、とりあえず抽象クラスというのは、それ自身がインスタンス化される為に存在するのではなく、その子クラス達の雛形として存在しているということを理解しておけば良いと思います。
abstractを上手く使って、効率のいいクラス設計を自分で出来るようになりたい人は、デザインパターンについて学んでみてください。こういうのが理解できるとかなりレベルアップするはずです。
今だけ→転職できなければ全額返金の「エンジニア転職保証コース」
絶対エンジニアになる!→テックエキスパート
フリーランスエンジニアの収入例を見てみる→レバテックフリーランス
コメント
シリーズ?通して読ませていただいてます。
他のサイトと目線のようなものが違うのかどの記事を読んでもわかりやすくてかなり助かっています!
曖昧に理解してたことがすっきりとわかるので読んでてとても楽しいです!
次の更新も楽しみにしています。
よければ例外処理なんて書いていただけると嬉しいなって・・
by 匿名 2017/03/02 15:17
>匿名さん
嬉しいコメントありがとうございます。
例外はいろいろあって難しいですよね。(^^;)
例外の前にインターフェイスについても解説したいなと思っています。
例外まで辿り着けるように頑張りますので、今後ともよろしくです。
by Nobuo@管理人 2017/03/04 15:41
Thank you very much.
This tutorial is helpful for me to learn Java.
by NguyenDucHieu 2017/07/29 13:44
いろんなサイトを読みましたが一番親切でわかりやすかったです。ありがとうございました。お金ができたら本をかいます(^3^)/
by 匿名 2018/01/19 00:35
ありがとうございました。
長年の「abstractって何のためにあるの?」という疑問が解消しました。
by IKA 2018/07/25 11:52
いろんなサイトでabstractについて調べていてどれも今ひとつピンとこなかったのですが、
このサイトではHumanクラスなどを使ってわかりやすく説明してあったので、ようやく理解することができました。
ありがとうございます!!
by 匿名希望25号 2018/09/30 22:44
とてもわかりやすかったです!インターフェイスぜひお願いしたいです!
by Yama 2018/11/27 17:00
うーんわかりやすすぎ!
by 匿名 2019/05/28 02:05
>Child is Superです。
日本語で書けば?
by 匿名 2019/08/28 22:59
楽しく読ませていただきました。
JAVA開発の初心者として、ただ勉強するためにこの内容を読んでいたのですが、読んでいて楽しいしわかりやすいと思っていて、なるほどIT開発というのはJAVAというのはそう難しくもないじゃないかという気持ちがありました。
そこで最後に皆さんのコメントも読んで初めて気づきました。
勉強していて楽と感じて、読んでいてわかりやすいと思ったのは、開発がJAVAが難しくないからではなかったんです。
この内容を書いている方が、面白くわかりやすく説明してくれているからなんです。
長いコメント失礼しました。
とてもありがたいという気持ちを、伝えたいです。
by Kazari 2019/10/11 09:45