参照型変数

Revised: Oct./4th/2004: Since: Dec./30th/2001

オブジェクトを参照するクラス型変数は、基本データ型の変数に対して、参照型変数と呼ばれます。配列の変数も参照型変数です。これらの変数に共通することは、型宣言初期化のほかに、生成という段階が存在することです。

変数の宣言方法

基本データ型変数

int i; 	//宣言
i = 10;	//初期化

変数の型を宣言して、値を明示的に代入しています。ローカル変数の場合は明示的に代入しないと使えません。フィールドの場合は、型宣言すれば、型に対応したデフォルト値が自動的に代入されます。

基本データ型の変数は、具体的な値を保持します。基本データ型変数同士の代入は、その変数が保持している値のコピーが行われます。例えば、基本データ型変数に5を代入し、この変数を別の基本データ型変数に代入すれば、メモリ上には二箇所に5が書き込まれて保持されます。

配列型変数

int[] array;       	//宣言
array = new int[4];	//生成
array[0]=10; array[1]=11; array[2]=12; array[3]=13;	//初期化

実は、配列も一つのオブジェクトであり、各種のメソッドフィールドが使えます。これらの殆どは java.lang.Object クラスで定義されたものです。明示的な代入が行われていない場合は、 null で初期化されます。

配列型変数は参照型変数なので、複数の要素の連なりを保持しているわけではなく、その参照(識別する為の ID)が保持されています。配列型変数を別の配列型の変数に代入しても、メモリ上の実体がコピーされるわけではありません。右辺から左辺に、識別する ID がコピーされるだけです。

new 演算子が、右辺で生成された配列を参照するIDを返しています。

クラス型変数

Date obj;        	//宣言
obj = new Date();	//生成
//初期化方法はクラスによりますね。

配列型とクラス型の参照型変数の場合は、生成 (construct) の段階で new 演算子を使っています。この演算子は、右辺で生成されたオブジェクトへの参照 (reference) を返します。上の例では、この参照は代入演算子 = によって、左辺で定義されているクラス型変数 obj に代入されています。オブジェクトが明示的に代入されていなければ、クラス型変数は null で初期化されます。

参照型変数に保持されるのは、生成された実体への参照であり、オブジェクトの実体はメモリ上の別の場所に存在しています。変数名で確保されたメモリ領域には、実体の参照(実体を識別する為の ID)が保持されています。

参照型変数を別の参照型変数に代入すると、左辺の変数には、右辺の変数が参照している実体ではなく、参照(実体の ID)がコピーされます。従って、実体はメモリ上に一つだけであり、その実体を参照する変数が二つできたことになります。

従って、代入する参照型変数と、代入される参照型変数があるとき、後者の参照するオブジェクトを操作すると、前者の参照するオブジェクトも操作されたことになり、その逆も成り立ちます。参照型変数を代入すれば、同じ実体を参照する ID がコピーされて、同じ実体を参照することになるわけです。

new 演算子が、右辺で生成されたオブジェクトを参照するIDを返しています。

参照型変数の比較

基本データ型の場合は、比較演算子 == で比較できます。

int i = 10, j = 10;
i == j;  //true

オブジェクトを比較する場合は、そのオブジェクトを参照している変数同士を、メソッド equals() を使って比較します。

obj1.equals(obj2);

== で比較すると、変数が保持している値が比較されます。参照型変数が保持しているのは実体への参照ですから、参照型変数同士を == で比較すると、実体を識別する ID が比較されることになります。別々のオブジェクトの実体を参照する ID は別のものですから、オブジェクトが等価であるかどうかには関係なく、必ず false が返ってきます。

別々のオブジェクトが実質的に同じかどうか比較する場合は、 equals() メソッドを使いいます。この場合は、例えば、 String 型のオブジェクトならば、同じ文字列を保持していれば true です。 Date 型のオブジェクトならば、同じ日付を保持していれば true です。

Date date1 = new Date();
Date date2 = new Date();
date1 == date2;  //false
date1.equals(date2);	//true

equals() メソッドは、 java.lang.Object クラスで定義されていますが、各々のサブクラスでの比較の目的に応じてオーバーライドされています。

サンプル

Equals.java:

//Date クラスのインポート
import java.util.Date;
class Equals {
	public static void main(String[] args) {
		Date date1 = new Date();
		Date date2 = new Date();
		System.out.println("date1: " + date1);
		System.out.println("date2: " + date2);
		boolean bln1 = (date1 == date2);     //false
		boolean bln2 = date1.equals(date2);  //true
		System.out.println("      ==: " + bln1);
		System.out.println("equals(): " + bln2);
	}
}

ここでは標準クラスライブラリの Date クラスをインスタンス化しています。このコードの2行目のように、利用するためにはパッケージも明示した完全限定名インポートするのが普通です。

このようにして二つのオブジェクトを生成し、それぞれを Date クラス型変数から参照しています。これらは全く同じ条件で作ったオブジェクトですが、別のものです。変数に代入されている参照は別のものを指していますので、 == で比較すると false です。しかし、同じ条件で作っているので、等価ですから、 equals() メソッドは true を返します。

C:\Java>javac Equals.java
C:\Java>java Equals
date1: Sun Mar 10 00:56:26 JST 2002
date2: Sun Mar 10 00:56:26 JST 2002
      ==: false
equals(): true

参照型変数の初期化

基本データ型の変数の場合は、フィールド以外のローカル変数の場合は、明示的に値を代入しておく必要があります。ローカル変数で明示的に代入していないとコンパイルを通りません。

一方、オブジェクト、配列を参照する参照型変数の場合は、フィールドであっても省略時の値(デフォルト値)が定義されており、生成と同時に代入されています。この値は null です。これは何も参照していないことを明示する値です。



Copyright © 2001-2004 SUGAI, Manabu. All Rights Reserved.
SEO [PR] !uO z[y[WJ Cu