クラスとは何でしょうか。クラスは一般的に「設計書」と呼ばれ「何かを実行する物体の設計書」と思って下さい。テレビの設計書。自動車の設計書...。「何かを実行」とは何でしょう。テレビであれば「電波を受信」「画像を写す」「音を鳴らす」...といったことができます。自動車なら「前進」「停止」「クラクションを鳴らす」...といったことができます。
これをプログラム風に記述すると以下のようになります。
class テレビ {
電波を受信 {
映像を写す;
音を鳴らす;
}
映像を写す {
・
・
・
}
音を鳴らす {
・
・
・
}
}
その設計書を使って製品を作ってみましょう。きっと以下のような手順で製品は作られるのでしょう。
- 設計書がどのようなものか、まずは設計書全体に目を通す。
- 設計書から察するに、完成した製品がどれぐらいの物(縦横幅重さ等)なのか想定しておく。
- 必要な部品を調達しておく。
- 先ほど想定したサイズ、重量等を考慮し、製品を置く場所を探す。きっと3Fの1号室の机の上に作れるはずだ。
- 実際に製造する。先ほど探しておいた場所に製造する。
- 完成したので、製品を置いた場所をメモし、作成を依頼した方に「3Fの1号室の机の上」に作成したと伝える。
設計書はJavaではクラスと呼びますが、設計書から作成された製品は何と呼ぶでしょう。Javaではインスタンスと呼んでいます。そしてクラスを参照しインスタンスを生成することを、インスタンス化する、もしくはインスタンスを生成すると呼びます。
では具体的にクラスを用いてインスタンス化してみます。インスタンス化にはnew演算子を利用します。記述順としては「new クラス名()」の順で記述します。
以下は先ほどのSampleクラスをインスタンス化する具体例になります。
new Sample();
では今度は具体的にコンピュータ風に考えてインスタンス化してみます。
- 設計書がどのようなものか、まずは設計書全体に目を通す。
- 設計書から察するに、完成した製品がメモリを何バイト使用する(以降は使用メモリ)のか想定しておく。
- 必要なパラメータがあれば予めもらう等、準備をしておく。
- 先ほど想定した使用メモリを考慮し、インスタンスを置く場所を探す。きっとアドレス番号12FB3A0番地に作れるはずだ。
- 実際にインスタンス化する。先ほど探しておいた場所にインスタンス化する。
- 完成したので、アドレス番号をメモし、作成を依頼した方に「12FB3A0番地」にインスタンス化したと伝える。
コンピュータ上では「東京都千代田区千代田1番1号」のような住所はありません。その代わりにトイレットペーパーのようなロール紙を1cm刻みで区切り、その先頭から何cm目を、アドレス番号(もしくは単にアドレス)と呼びます。
このアドレスですがインスタンス化した瞬間にしか受け取ることはできません。なのでインスタンス化したときには忘れずに受け取って記録しておきましょう。「new演算子でインスタンス化するとnewが戻り値を返す。その戻り値が生成したアドレス。」のように覚えましょう。
では生成したアドレスを変数に記録しましょう。変数は何型でしょうか。現時点ではインスタンス化したクラスと同一の型としましょう。
Sample instance = new Sample();
ここまでは全てのメソッドにstatic修飾子がついていましたが、static修飾子はどのような意味があるのでしょうか。static修飾子がつくとそのクラス全てで共通、つまり設計書が同じなら必ず同じ、static修飾子がつかないとインスタンスで固有という意味になります。ついていないメソッドはインスタンスメソッドと呼ばれ、ついているメソッドはクラスメソッド(もしくはスタティックメソッド)と呼ばれます。つまりクラスメソッドはインスタンスに関係がないためインスタンス化されていなくてもいきなり呼び出せるメソッドで、インスタンスメソッドは生成されたインスタンスからしか呼び出すことができません。static修飾子がついていると「クラスで共通」、ついてないと「インスタンス毎に異なる」ということになります。
先ほどの例を考えてみます。mainメソッドで考えてみましょう。メインメソッドを呼び出す際に、new演算子は登場していません。つまりJavaが、インスタンス化されていないSampleクラスのmainメソッドを、いきなり呼び出したということです。
public static void main(String[] args) {
クラスメソッドとインスタンスメソッドどちらがいい?と問われてもどちらにも長所短所があります。現時点では、なるべくインスタンスメソッドで実装するようにして下さい。(つまりmainのみstatic修飾子をつけましょう)
話はかわりますが、ここで定数を思い出してみましょう。定数にはstatic修飾子がついていました。定数の性質上2度と変更されることのない値なのですから、インスタンス毎に値が異なることもないため、クラスに1つだけで十分です。なのでクラスで唯一1回定義されればよいのでstatic修飾子がついていたのです。
先程までのSampleクラスをインスタンス化するよう変更してみます。hogehogeメソッドはインスタンスメソッドなので、インスタンス化してからでないとhogehogeメソッドは呼び出せません。
class Sample {
static final String MESSAGE_1ST = "私は";
static final String MESSAGE_2ND = "です。";
static final String MESSAGE_3RD = "歳" + MESSAGE_2ND;
public static void main(String[] args) {
Sample instance = new Sample();
String message;
message = instance.hogehoge(args); // インスタンス化してからでないとhogehogeメソッドは呼び出せない。
System.out.println(message);
}
String hogehoge(String[] args) {
String name;
name = args[0];
int age = Integer.parseInt(args[1]);
String message;
message = MESSAGE_1ST + name + MESSAGE_2ND + age + MESSAGE_3RD;
return message;
}
}
では今度は複数のクラスを使用してみます。メソッドが2つ存在したので、それを2つのクラスとします。
class Starter {
public static void main(String[] args) {
Sample instance = new Sample();
String value = instance.hogehoge(args);
System.out.println(value);
}
}
class Sample {
String hogehoge(String[] args) {
return "Hello";
}
}
>javac Sample.java
>javac Starter.java
>java Starter
Hello
上記の2クラスを使用する例にて、コンパイルを2回行なっていますが、コンパイルの順序を逆にしなさい。
またその際に何が起こるか予想してから、実行しなさい。最終的に実際に何がおこったか検証しなさい。