前提知識
「オブジェクト指向」というコンセプトを最初に提唱したのは米ゼロックス社に在籍していたアラン・ケイ*1氏であり、彼が率いるチームが開発したプログラミング言語Smaltalkにて確立された。現在、オブジェクト指向という言葉を聞くと、PythonやJavaといったプログラミング言語を思い浮かべるかもしれない。【Javaの備忘録】という文言をタイトルに入れておいて申し訳ないが、この認識は正確ではない。
オブジェクト指向とはソフトウェア開発の総合技術のことだ。
とはいえその総合技術全てを説明するには、一記事ではとてもじゃないが語れない。という訳で本記事では、Javaをオブジェクト指向のコンセプトを満たす言語である根拠に絞って理解を深めていきたい。オブジェクト指向を一言でまとめると、「ソフトウェアの再利用や保守をしやすくすることを重視する技術」であり、個々の部品の独立性を高めることで、それらの部品を組み立てることで機能を実現するというような考え方である。
オブジェクト指向プログラミングの3大要素と呼ばれるものがあり、それは下記の3つだ。それぞれ個々の部品の独立性を高めるために重要な意味を持っている。
- クラス化
- ポリモーフィズム
- 継承
クラス化
Javaにおいて、モノの「種類」や「分類」といったクラスを定義することができる。クラスに具体的な名前などを別途定義することでインスタンスという「個別のモノ」を作成し、操作することができるようになる。これがJavaの基本的な構文だ。
もう少し具体例を挙げて説明しよう。
クラスで定義するモノの「種類」や「分類」というのは、「人間」というような特定できる個別の要素(江戸川コナン、野比のび太、とか)を列挙できるモノのことを指す。試しに「人間」というクラスをJavaで定義してみると下記のような感じになる。
public class Person { String name; // 個人名 public Person(String name) { this.name = name; } void selfIntroduction(){ System.out.println("私は" + name + "です"); } }
それぞれ下記のような個人情報を与えることで、「人間」(=Person)に特定の個人というインスタンスを作成し、操作することが可能となるわけだ。ちなみにselfIntroductionはPersonクラスに用意されているメソッドであり、今回の場合は自己紹介をするようにnobitaにお願いするようなイメージである(このイメージからメッセージバッシングとも呼ばれる)。
Person nobita = new Person("野比のび太"); nobita.selfIntroduction();
ポリモーフィズム
英語では「色々な形に変わる」というような意味を持ち、「同じようなクラスに共通するメソッドをくくりだす」といったようなものだ。もう少し具体例を出して説明しよう。
クラスの説明では「人間」という分類をクラス化しているが、「人間」は「動物」という分類の一つであると考えることも可能だ。「動物」という分類の中には「人間」だけではなく、「犬」や「猫」といった分類も存在する。それら「犬」「猫」「人間」クラスで共通して利用できるメソッドは、「動物」というクラスの中で抽象化して定義して使いまわすことができる。
abstract class Animal { abstract String cry(); }
上記のようなAnimalクラスを作成し、「人間」クラスや「犬」クラスで共通化できそうなcryメソッドをabstractという抽象化メソッドとして定義した。抽象化メソッドとはその中身自体は定義されておらず、別途クラスで定義しなければならない。下記はAnimalクラスのcryメソッドを定義したクラスである。
class Person extends Animal{ String name; // 個人名 public Person(String name) { this.name = name; } void selfIntroduction(){ System.out.println("私は" + name + "です"); } @Override String cry() { return "。゚(゚´Д`゚)゚。"; } } class Dog extends Animal { String name; Dog (String name){ this.name = name; } @Override String cry() { return "ワンッ"; } }
cryメソッドを定義したPersonクラスとDogメソッドを利用してみると(ついでにselfIntroductionも利用)、ちゃんとそれぞれの定義したものが反映されていることが分かる。
実行コード
public class Main { public static void main(String[] arg){ Person nobita = new Person("野比のび太"); Dog pochi = new Dog("ポチ"); nobita.selfIntroduction(); System.out.println(nobita.cry()); System.out.println(pochi.cry()); } }
実行結果
私は野比のび太です
。゚(゚´Д`゚)゚。
ワンッ
継承
「人間」は「動物」クラスの中に含まれる部分集合、「犬」もまた「動物」クラスの中に含まれる部分集合という関係がある。これをプログラム的に表現すると、「動物」クラスは「人間」クラスのスーパークラスであり、「人間」クラスは「動物」クラスのサブクラスであるというように説明できる。つまり「動物」クラスでできることは、「人間」クラスでもできるし、「犬」クラスでもまたできるべきであろう。
サブクラスではスーパークラスとの間にある差分のみ定義することを継承という。
abstract class Animal { abstract String cry(); void run(){ System.out.println("走る"); } }
おそらく「犬」も「人間」もするであろう動作 ”走る” をrunメソッドとしてスーパークラスに定義した。
class Person extends Animal{ String name; // 個人名 public Person(String name) { this.name = name; } void selfIntroduction(){ System.out.println("私は" + name + "です"); } @Override String cry() { return "。゚(゚´Д`゚)゚。"; } } class Dog extends Animal { String name; Dog (String name){ this.name = name; } @Override String cry() { return "ワンッ"; } }
PersonクラスとDogクラスでそれぞれAnimalクラスを継承(=extends)したが、runメソッドは再定義などしていない。Animalクラスで定義されているものをそのまま使うことを想定している。PersonクラスのインスタンスとDogクラスのインスタンスそれぞれのrunメソッドを実行した結果は下記の通り。それぞれ同じ内容「走る」が表示されている。
実行コード
public class Main { public static void main(String[] arg){ Person nobita = new Person("野比のび太"); Dog pochi = new Dog("ポチ"); nobita.selfIntroduction(); System.out.println(nobita.cry()); nobita.run(); System.out.println(pochi.cry()); pochi.run(); } }
実行結果
私は野比のび太です
。゚(゚´Д`゚)゚。
走る
ワンッ 走る
まとめ
記事を書くに当たり下記の書籍を参考にさせていただいた。オブジェクト指向に関わるソフトウェア開発の総合技術に関する部分やプログラミング言語に関することなど、オブジェクト指向に対して様々な方向性から説明してあるため分かりやすい。オブジェクト指向の弱点である抽象的な説明がどうしても多くなるという点に言及しつつ、その弱点をどうにかして解消して説明しようとしているのが好印象だ。
*1:パーソナルコンピュータの父と呼ばれる。会社の経営陣に研究内容の未来予測をしつこく尋ねられた時に答えた「未来を予測する最善の方法は、それを発明することである」という言葉が有名