はじめに
仕事で初めてJavaを触ったので、そのバイブルとしてよく挙げられる本書を手に取りました。これはそれを読んだ際のメモです。インプットしたことを特に添削もせずそのまま書き下している感じなので、日本語的にかなりおかしな部分や自分の理解の誤りなどもありますが、温かい目で見てください。随時修正していく予定です。
本書の概要
オブジェクト指向の歴史とどのようにしてソフトウェア開発では利用されるかという部分に着目して具体的なコードというよりはその概念について説明してくれる。
第3章 OOPを理解する近道はプログラミング言語の歴史にあり
機械語
初めはマシン語でプログラムは書いていたが、流石に不便だったため、アセンブリ言語は開発された。
構造化プログラミング
これでもわかりづらかったので、続いてFORTRANなどの高級言語が登場した。コンピュータの発達に伴い、エンジニアが足りないという未来が危惧されたため、より分かりやすい言語の開発が求められた(GOTO文の廃止)。それが構造化プログラミングである。
そしてオブジェクト指向へ
構造化プログラミングは、逐次処理、条件分岐、繰り返し、の3つでプログラムを構成する。そして、保守性を高めるためにサブルーチンの独立性を高めることも求められた。ただ、それによってグローバル変数が多用され、かえって保守性の低下を招いた。そこでローカル変数と引数の値渡しという仕組みが導入された。ローカル変数はサブルーチンの中で使われる変数で、値渡しは元の変数の値をコピーしてサブルーチンに渡すことである。これにより、保守性を向上させることはできたが、新規でプログラムを作ることに対するサポートはまだ不十分であった。グローバル変数の問題や弱い再利用などに対処する必要があった。
第4章 OOPは無駄を省いて整理整頓するプログラム技術
OOPでクラス、ポリモーフィズム、継承という新しい概念が導入された。これは構造化プログラミング言語の問題点であった。グローバル変数(プログラムのどこからでもアクセスできてしまう。グローバル変数を変更する際にそれがどこに影響を及ぼすかプログラム全体を逐一確認しないといけなくなる)、貧弱な再利用を解決するための仕組みである。
クラス
- サブルーチンと変数をまとめる
クラスにより変数とサブルーチンをまとめることができる。このまとめたグローバル変数をインスタンス変数、サブルーチンをインスタンス変数という。メリットは以下の通り。- ソースコードの量を減らせる
- 名前づけが簡単
- サブルーチンを探しやすくなる
- クラスのみで使う変数やサブルーチンを隠す
インスタンス変数にアクセスできるメソッドを制限する。これによりプログラムの保守性を低下させていたグローバル変数を使わずにすむ。
public class TextFileReader {{
private int fileNum;
public void open(String pathName)
public void close()
public char read()
}}
privateをつかることでfileNumへのアクセスはクラス内のメソッドに限定される。publicをつけることで明示的に公開することができ、どこからでも呼び出せるようになる。
- 1つのクラスからインスタンスをたくさん作る
インスタンスはクラスを定義しておけば実行時にいくらでも作ることができる(メモリ領域が確保できる)。ファイルや顧客情報など、同種の情報を複数同時に扱う処理であっても、そのクラス内部のロジックをシンプルにできる(クラス側ではインスタンスが複数同時に動くことを意識しなくて良いため)。
ポリモーフィズム
サブルーチンを呼び出す側を一本化すること。すなわち、共通サブルーチンを作ること。
例として、今度はネットワーク経由で発信された文字列を読み込むクラスを作成する。
例:NetworkReaderクラス
public class NetworkReader {{
public void open()
public void close()
public char read()
}}
ポリモーフィズムでは呼び出されるメソッドの引数や戻り値は統一する必要があるため、先ほどのTextFileReaderのopenメソッドを引数にファイルパスを指定する方法から新たにインスタンス作成時にファイルのパス名を指定するようにする。
例:ポリモーフィズムを利用するための準備
public class TextFileReader {{
private int fileNum;
// インスタンス作成時に呼び出されるメソッド
// 引数にパスを受け取る
public TextFileReader(String pathName)
public void open()
public void close()
public char read()
}}
また、呼び出す側で、テキストファイルかネットワークかを意識しなくていいようにするために、新しくTextReaderクラスを用意する。
例:TextReaderクラス
public class TextReader {{
public void open()
public void close()
public char read()
}}
そして、TextFileReaderとNetworkReaderがこのTextReaderに従うことを宣言するために、extendsを使って継承する。
public class TextFileReader extends TextReader {{
// 省略
}}
public class NetworkReader extends TextReader {{
// 省略
}}
これを利用することで、入力元がファイルであってもネットワークであっても文字数をカウントする以下のようなプログラムを書くことができる。
int getCount(TextReader reader) {
int charCount = 0;
while (true) {
char = reader.read();
charCount ++;
}
return charCount;
}
新たにコンソールから入力された文字列を読み込むクラスを追加したとしても、上記のプログラムを修正する必要はない。
継承
クラスの共通部分を別のクラスにまとめる仕組み。共通化したクラスをスーパークラス、それを利用するクラスのことをサブクラスという。
OOPではクラスを型として利用
int getCount(TextReader reader) {
// 省略
}
型にクラスを指定した変数や引数、戻り値に対して、そのクラス以外のインスタンスを格納しようとするとコンパイルエラーになる。こうした型チェックによりプログラマーはより楽ができるようになった。
パッケージ
「まとめる」仕組みとして登場したクラスをさらにまとめるための仕組み。クラスと違ってメソッドやインスタンスを定義することはできない。ディレクトリに近いイメージ。
例外
戻り値とは違う形式で、メソッドから特別なエラーを返す仕組みのこと。
- 例外を宣言しているメソッドを呼び出す側では、例外を処理するロジックを正しく書いていないと、きちんとエラーが出力される
- 例外を宣言しているメソッドを呼び出す側では、エラー発生時に特別な処理を行わずに、さらに上位のメソッドにエラーを使えるだけですむ
ガベージコレクション
インスタンス作成時に行ったメモリ領域を自動で削除する仕組み。
第5章 メモリの仕組みの理解はプログラマのたしなみ
OOPを使って書いたプログラムがどのようにして動くかを理解する。これにより、メモリ管理やデバック時にこれに関連した問題が発生した場合にも対応できるようになる。
中間コード
コンパイラを使って機械語に依存しない中間コードに変換し、これをさらにインタプリタによって解釈して実行する。コンパイラ方式とインタプリタ方式の両方を合わせたような実行方式である。
メモリ管理
- 静的領域
プログラムの開始時に確保され、プログラムが終了するまで配置が固定される領域のこと - ヒープ領域
プログラムの実行中にアプリケーションから必要なサイズを要求することで割り当てを行い、不要になれば元に戻す - スタック領域
スレッドの制御のために使うメモリ
クラス情報は静的領域にロードされる。インスタンスを作成すると、そのクラスのインスタンス変数を格納するために必要な大きさのメモリがヒープ領域に割り当てられる。従来のプログラミングではヒープ領域を使わず、コードとグローバル変数を静的領域に配置し、サブルーチン呼び出しの情報はスタック領域を使って受け渡すことでプログラムを実行していた。しかし、OOPではこのようにヒープ領域を大量に使って動く。
例えば、以下のようなTextFileReaderのインスタンスはヒープ領域に格納される。
TextFileReader reader = new TextFileReader(); // readerには
また、インスタンを格納する変数(この例ではreader)にはインスタンスのポインタが格納される。
第6章 OOPがもたらしたソフトウェアとアイデアの再利用
OOPは以下の2つの再利用をもたらした
- ソフトウェアの再利用(クラスライブラリ、フレームワーク、コンポーネント)
- アイデアやノウハウの再利用(デザインパターン)
デザインパターン
設計のパターンのこと。プログラム開発内で、頻繁に現れるクラス構造に名前をつけてパターン化したものを指す。
第7章 汎用の整理術に化けたオブジェクト指向
ソフトウェアは現実世界をそのまま表現できるだろうか。例えば、病院のシステムは、現実世界の病院をそのまま表現していないように、コンピュータが現実世界をまるまる置き換えることはできない。つまり、コンピュータが肩代わりするのは、一部の現実世界に過ぎず、プログラミングの前段階に現実世界の業務分析や要件定義などを行う必要がある。このような作業を上流工程と呼ぶ。
上流工程におけるオブジェクト指向
- 集合論
例:犬がクラスで、ポチやタローがインスタンス - 役割分担
例:レストランでウェイトレスに注文すること、A社に靴を注文すること
個人的に勉強になった部分
クラス・インスタンス・ポリモーフィズム
クラスは種類(犬、国、歌手...)で、インスタンスはクラスから生成するモノ(ポチ、タロー、中国、アメリカ、宇多田ヒカル...)。集合と要素の関係。ポリモーフィズムは相手がどのクラスのインスタンスであるかを意識することなく操作できる仕組み。泣けという命令を犬に送れば「ワン」、カラスであれば「カー」のように。