WisdomSoft - for your serial experiences.

4.1 クラスとインスタンス

クラスの宣言と new 演算子による新しいインスタンスの生成について説明します。

4.1.1 クラスの宣言

第1章から第3章までに学習した内容は、コンピュータの動作を指示するための命令の集合を記述する、最もプログラム的な部分でした。流れ制御や変数などは、C 言語を代表とする従来の手続き型言語と概念は同じです。しかし、Java 言語はオブジェクト指向型言語であるという点で C 言語と大きく異なります。

オブジェクト指向の実行単位は、手続き型のようなプログラムの流れではなく、プログラムに与えられた役割を 1 つの部品として考えます。役割は様々なものが考えられます。例えば、従業員や顧客の個人情報を管理する役割が与えられたとしましょう。個人情報には名前や住所、年齢、電話番号などの情報が含まれています。さらに、個人情報に含まれている電話番号や住所も、1 つの役割として独立できます。プログラムは電話番号から地域を特定したり、住所から郵便番号を割り出すなど、役割の関係が求められる可能性があるためです。複雑な処理は、役割を細分化して単純にすることができるのです。

1 つの役割を果たすための基本的な部品をクラスと呼びます。Java 言語ではクラスが実行単位であり、必ず 1 つ以上のクラスから成り立っています。これまでのプログラムでもクラスを宣言してきましたが、もう一度 class キーワードを使ったクラス宣言をおさらいしてみましょう。

クラス宣言
class クラス名 { 本体 }

これまでのプログラムでは、常に Test という名前のクラスを宣言していました。

class Test { ...

これをコンパイルした結果、Test.class というバイトコードが生成されていました。Java では、クラスが 1 つの部品として扱われるため、クラスごとに 「*.class」 ファイルを生成します。クラスは必要な数だけ自由に宣言することができます。

コード1
class Test {
	public static void main(String args[]) { }
}

class Kitty { }
class Puppy { }

コード1は、Java コンパイラがクラスごとに分割してクラスファイルを生成することを証明します。このプログラムでは、従来の Test クラス以外に Kitty クラスと Puppy クラスを宣言しています。これらのクラスの本体は何も記述していないため、実質的な機能は存在しません。これをコンパイルすれば、Test.class、Kitty.class、Puppy.class が生成されることを確認できます。

Java 仮想マシンは、プログラムの実行中に、動的にこれらのファイルをメモリの読み込みます。これは、Java の世界ではシステムそのものが、実行ファイルを動的に読み込むダイナミック・リンク(プログラムの部品を実行時に読み込み、目的の機能を呼び出す仕組み)の機能を提供していると考えられます。開発者はダイナミック・リンク用のコードと実行ファイルを分け、個別に管理したり、コンパイルするといった従来の面倒から解放されるでしょう。

4.1.2 インスタンスの生成

クラスを宣言するだけでは、メモリが割り当てられたり、何らかのプログラムが実行されることはありません。作成したクラスを利用するには、必要になった時点でクラスを実体化しなければなりません。この、クラスの実体のことをインスタンスと呼びます。クラスの実体であるインスタンスを作成することによって個別のメモリが割り当てられます。

インスタンスを生成するには、クラス・インスタンス生成式を用います。基本的なクラス・インスタンス生成式は new キーワードとそれに続くクラス名で構成されます。例えば、Kitty クラスのインスタンスは次のように生成します。

new Kitty();

これで、指定したクラス名のインスタンスが生成されます。生成されたインスタンスは、互換性のあるクラス型の変数に代入することができます。クラスは 1 つの型であり、クラスが他の変数を作成することができます。生成したインスタンスはクラス型の変数に代入し、保存することができます。

インスタンスはしばしばオブジェクトとも呼ばれますが、オブジェクトという表現はやや広義です。本書では、クラスの実体を明確に意図する場合はインスタンスと呼び、それ以外ではオブジェクトと表現します。

コード2
class Kitty { }

class Test {
	public static void main(String args[]) {
		Kitty obj1 = new Kitty();
		Kitty obj2 = new Kitty();
		
		System.out.println(obj1);
		System.out.println(obj2);
	}
}
実行結果
>java Test
Kitty@c78e57
Kitty@5224ee

コード2は Kitty クラスを宣言しています。プログラムは Kitty クラス型の変数 obj1 と obj2 に、それぞれインスタンスを生成して格納します。個々のインスタンスは独立し、それぞれが独自にメモリを占有しています。これは、obj1 と obj2 を println() メソッドに渡し、画面に表示させることで確認することができます。

クラス型の変数を println() メソッドに渡すと、実行結果のようなクラス名と 16 進数の数値が表示されます。これは、次のような関係を持ちます。

クラス名@ハッシュコード

アットマークの左側にはクラス名が表示されます。実行結果では Kitty と表示されているため、変数が表すインスタンスは Kitty 型であることが確認できました。

右側の数値はハッシュコードと呼ばれるもので、オブジェクトが等しい場合は常に同じ値であることを保証する数値です。指紋のようなものだと考えてください。どのような値が表示されるかは、実行環境やタイミングによって変化します。コード2の実行結果では、異なった数値が表示されているため obj1 と obj2 に格納されているオブジェクトは異なることを証明しています。