パッケージ(2): 他のパッケージの利用・アクセス修飾子、クラスの基礎(3): コンストラクタ(メソッドの一種)

前回のまとめ

  • メソッドの定義・利用(呼び出し)について
    • C言語とだいたい同じ
    • メソッドが所属するクラスのフィールドにアクセス(読み・書き)できる。
    • メソッドが所属するクラスのメソッドを呼び出すことができる。
    • 他のインスタンスのメンバーは「インスタンス名.メンバー名」で使える。
  • 課題の解答例: MedicalRecord.java(48〜56行目)

パッケージ(2): 他のパッケージの利用・アクセス修飾子

他のパッケージに所属するクラスの利用方法とアクセス修飾子の機能について確かめよう。

  1. パッケージ「d00000.lecture06」を作成する。
  2. そこにMain1クラスを作成する。
  3. Main1クラスにmainメソッドを作成する。

最終的なソースコード: Main1.java

他のパッケージに所属するクラスを直接使うにはクラス名の前に「パッケージ名.」をつける(9行目)。

d00000.lecture05.MedicalRecord mr1 = new d00000.lecture05.MedicalRecord();

import文を使うと「パッケージ名.」を省略することができる(3行目)。

import d00000.lecture05.MedicalRecord;

この場合、単に「MedicalRecord」と書いた場合は「d00000.lecture05.MedicalRecord」として扱われる。同じ名前のクラスを複数使いたい場合は、パッケージ名を省略できるのは1つだけ。ちなみに、import文なしでパッケージ名を省略した場合は、同じパッケージのものを指す。

注意: 教科書の説明だと、import文を使わないと他のパッケージのクラスが使えないように読めるが、ここで確かめたように、そうではない。import文は単に他のパッケージのクラスを利用するときの「パッケージ名.」を省略できるようにする、という機能である。C言語の#includeとは全然違う。

他のパッケージで使えるクラスは、classの前に「public」というアクセス修飾子がついていなければならない。また、インスタンス化ができたとしても、その中のメンバーにも適切なアクセス修飾子がついていなければならない。「クラスにつくアクセス修飾子」と「メンバーにつくアクセス修飾子」の2種類があることに注意しよう。

クラスの基礎(3): コンストラクタ(メソッドの一種)

メソッドを追加して、MedicalRecordクラスをもっと「使える」クラスにしていこう。

  1. d00000.lecture06にMain2クラスを作成する。
  2. Main2クラスにmainメソッドを作成する。
  3. d00000.lecture05のMedicalRecord.javaをd00000.lecture06にコピーする(前回と同じくリファクタリングコピーを使う)。

最終的なソースコード: Main2.javaMedicalRecord.java

これまでの利用の仕方を確認していこう(Main2.java: 5〜11行目)。8〜10行目をコメントアウト(コメントにすること)して実行してみよう。このようにフィールドをセットし忘れたりするとおかしな動作をすることがある。クラスの設計については色々な考え方があるが、ここでは、「セットしやすいように工夫する」とか「セットし忘れても大丈夫なようにする」といった考え方で改良してみよう。

まずは、フィールドをセットする専用のメソッドを用意してみよう(Main2.java: 15行目、MedicalRecord.java: 58〜68行目)。これを使うことで、3つのフィールドを1行でセットできる。thisについては教科書の110ページを参照すること。メソッドの引数とフィールドの名前が被った場合、メソッドの本体では引数の方が優先して使われる。このような名前が被った状態でフィールドの方を使うためには「this.」をつけてフィールドの方であることを示す必要がある。また、表示する文字列を作るメソッドも用意しよう(Main2.java: 16行目、MedicalRecord.java: 70〜78行目)。これでだいぶシンプルになった。

次は、インスタンス化したら、デフォルトで値を設定するということを考えよう。これにはコンストラクタ(constructor)というちょっと特殊なメソッドを追加することで実現することができる。コンストラクタは、インスタンス化のタイミングで自動的に実行されるメソッドで、次のようにして定義したメソッドがコンストラクタにとして扱われる。

  • メソッド名はクラス名と同じにする。
  • メソッドの戻り値(返り値)の型は記述しない。

まずは引数なしのコンストラクタを追加しよう(MedicalRecord.java: 80〜91行目)。いつものようにインスタンス化する(Main2.java: 19行目)と、このコンストラクタが実行される。最初はMedicalRecord.javaの85行目はコメントを外して、コンストラクタが実行されたことを確認しよう。

次に、引数ありのコンストラクタを追加しよう(MedicalRecord.java: 93〜104行目)。これを使えば、任意の値をインスタンス化の時に設定することができる(Main2.java: 23行目)。

コンストラクタを作ると、配列を作成することも簡単になる(Main2.java: 26〜30行目)。また、任意の値とともインスタンス化することができるので、名前をつけずにインスタンス化し、そのメソッドを実行するなんてことにも利用しやすくなる(Main2.java: 33行目)。

コンストラクタにまつわるハマりどころ

実は、インスタンス化にはコンストラクタが絶対に必要。

今まで、コンストラクタを定義してなかったのにインスタンス化ができていたのはなぜか? コンストラクタを1つも定義しないと、デフォルトコンストラクタが作成される。これがインスタンス化に使われる。

ハマりどころ: コンストラクタを1つでも定義すると、デフォルトコンストラクタは作成されない。引数ありのコンストラクタだけを定義した場合、引数なしの形でインスタンス化することができない。