市販の入門書で不足している説明
評価項目中、ぜひ押さえておきたい項目について詳しく説明します。
シグネチャ
オーバーロード・オーバーライドを説明する上で必要となるため、これら2つの項目の前に説明します。『明解Java』では「メソッドのシグネチャとは、メソッド名と仮引数の個数と型の組み合わせのことである」とあります。仮引数の名前が同じであることは要件ではありません。また、戻り値の型が同じであることも要件ではありません。この定義で十分ですが、修飾子やthrowsする例外も要件ではないことに注意してください。修飾子のまとまった説明は『Java言語プログラミングレッスン 下』のp32にあります。列挙するとfinal、abstract、static、synchronized、native、さらにはアクセス修飾子と呼ばれるpublic、protectedまたはprivateがあります。
オーバーロード(メソッドの多重定義)
オーバーロードはシグネチャが異なれば同じ名前のメソッドを複数定義できることを指します。シグネチャが十分理解できていないと、『明解Java』で説明してあるように、戻り値の型だけが違うメソッドを定義したり、仮引数の名前が違うだけのメソッドを定義しようとする間違いを犯します。アクセス修飾子やthrowsする例外だけが異なる定義はできません。
デフォルトコンストラクタ
デフォルトコンストラクタと引数を持たないコンストラクタを混同しがちです。デフォルトとは、何も指定されない場合に適用されるもののことを指します。従って、デフォルトコンストラクタとはコンストラクタを定義しない場合、自動的に作成されるコンストラクタです。その中はsuper();であり、親クラスのコンストラクタが呼ばれるようになっています。他方、引数を持たないコンストラクタとは、文字どおり、引数を持たないコンストラクタのことであり開発者が定義するものです。この場合、デフォルトコンストラクタが自動的に作成されることはありません。引数を持たないコンストラクタはJava Beansの要件の1つです。
アクセサ(setter/getter)
カプセル化と言うとprivateなフィールドにアクセスするためにgetter/setterを作成することと勘違いする入門者が多くいます。実務では値は取得したいが設定したくない場合、フィールドの設定はコンストラクタで行い、setterを作成しないようにします。このように値が初期化時以外変更しないフィールドをimmutable(不変の)であると言います。すべてのフィールドがimmutableであるオブジェクトを、immutable object(不変オブジェクト)と呼びます。カプセル化=(privateフィールド作成+setter/getter作成)ではありません。setterは安易に用意せず、必要であるかを十分検討するようにしてください。
静的インポート宣言
インポート宣言はご存じと思いますが、意外と知られていないのが静的インポート宣言です。JavaSE5より前のバージョンを使って、数学の関数を使ったアルゴリズムを記述するためには、例えばMath.EやMath.PIなどの定数や、Math.sin(x)、Math.cos(y)など必ずMathを付けなければならず、かえって読みづらいプログラムになった記憶があります。JavaSE5で静的インポートが導入されてからは、記述が楽になり可読性も高まりました。
方法は簡単で、import static java.lang.Math.*;のようにstaticを付けるだけです。これだけで、Mathクラスの定数やクラスメソッドをMathを付けずに記述でき、すっきりします。Mathクラスは定数とメソッドがすべてstaticのため、Mathクラスを使用する場合はぜひお薦めします。そのほかによく使うクラスではラッパークラスがあります。Integer、Booleanなどのラッパークラスのメンバすべてがstaticというわけではありませんが、頻繁に使用するものはstaticのため静的インポートに向いています。
アクセス修飾子protected
アクセス修飾子にはpublic、private、指定なし(デフォルト)、protectedの4つがあります。アクセス修飾子とはフィールドやメソッドが外部のどこからアクセスできるかを指定するための修飾子です。指定なしの場合はデフォルトの範囲になります。デフォルトはパッケージ内のクラスからのアクセスを、publicはすべてのパッケージのクラスからアクセスを許容します。privateはクラスの外部からのアクセスを禁止します。あまり使われないのがprotectedです。アクセス修飾子の説明は入門書で扱われるのみで、この機会を逃すと知らないまま終わってしまうため、ここでprotectedの重要性を説明します。
フレームワークを自作する際には、protectedが活躍します。今ではフレームワークの概念がやや甘くなってきています。以前はIoC(Inversion of Control)の特徴を持ち、ある程度大きな単位で同じような機能を実現するためのものをフレームワークと読んでいました。今では単なるクラスライブラリでさえフレームワークと呼ぶ技術者が増えています。ここではIoCの特徴を持つものをフレームワークと呼ぶこととします。
クラスライブラリとフレームワークの決定的な違いは、クラスライブラリは作成するプログラムから利用するものであり、フレームワークは作成するプログラムが利用されるものであることです。フレームワークを「ある程度大きな単位で同じような機能を実現するためのもの」と筆者が乱暴に定義しましたが、入門段階を終え使うことになるであろうStrutsやSpringなどはWebアプリケーションという大きな単位で同じような機能を実現するためのものです。StrutsやSpringなしでWebアプリケーションを作る弊害は、サブシステム間で共通な機能を持った異なるクラスが作成されることです。これでは非常に無駄です。共通機能を洗い出すことで各サブシステムで共通のクラス群を使用できるようにし、サブシステム独自の機能部分だけを開発者に開発させ、全体として動くようにするためのものがフレームワークです。つまり、独自の機能を持ったプログラムがフレームワークに使用されるのです。クラスライブラリの場合は用意されたクラスをコントロールしていましたが、フレームワークの場合は、コントロールされる側になるのです。まさしくIoC(Inversion of Control)、コントロール(制御)の逆転です。
protectedアクセス修飾子は同じパッケージ内から、あるいは継承したクラスからアクセス可能です。フレームワークはあるパッケージ名で作成されます。独自の機能部分は別のパッケージ名で作成されるはずです。このような場合、すべてのパッケージのクラスからフレームワークにアクセスされるのでは困ります。サブシステム独自の機能を持ったクラスのみがフレームワークによりコントロールされるためにはprotectedがまさにふさわしいアクセス範囲です。いつかフレームワークを自作する時が来たときに思い出してください。頑丈なフレームワークを作成する場合の基本です。非常に脆いフレームワークが自作されているのを多く見るようになり、あえて詳細に説明しました。
継承クラスのコンストラクタでのsuper
「継承されるものとされないもの」を後述しますが、コンストラクタは継承されません。従って、スーパークラスのコンストラクタの機能を使用するにはsuperを使用する必要があります。引数は持っていても、持っていなくても構いません。条件として、継承するコンストラクタの最初でsuper()を呼び出す必要があります。
