▲ | ▼ | 目次 | KnowHowTop |
ここでは Java の基礎知識としてオブジェクトの比較についての解説をします。
オブジェクトの比較は、そのオブジェクトの参照が一致しているかを比較するため、同じ値であっても参照が異なる場合には true にはなりません。
Integer i1 = new Integer("1"); Integer i2 = i1; Integer i3 = new Integer("1"); if ( i1 == i2) { System.out.println("== の比較で i1 と i2 は等しい"); } else { System.out.println("== の比較で i1 と i2 は等しくない"); } if (i1 == i3) { System.out.println("== の比較で i1 と i3 は等しい"); } else { System.out.println("== の比較で i1 と i3 は等しくない"); }
プログラムの実行結果は以下のようになります。
== の比較で i1 と i2 は等しい == の比較で i1 と i3 は等しくない ← 同じ値でも等しくない
これは、オブジェクトが参照データ型であるため、オブジェクト内には実際の値が格納されているメモリのアドレスを保持しているからです。
オブジェクトに格納されている値を比較するには、 epuals( ) メソッドを利用します。
Java でオブジェクトの値を比較するには、equals( ) メソッド使用します。
先に示した、例を equals( ) メソッドを使用して書き換えると次のようになります。
Integer i1 = new Integer("1"); Integer i2 = i1; Integer i3 = new Integer("1"); if (i1.equals(i2)) { System.out.println("equals() の比較で i1 と i2 は等しい"); } else { System.out.println("equals() の比較で i1 と i2 は等しくない"); } if (i1.equals(i3)) { System.out.println("equals() の比較で i1 と i3 は等しい"); } else { System.out.println("equals() の比較で i1 と i3 は等しくない"); }
プログラムの実行結果は以下のようになります。
equals() の比較で i1 と i2 は等しい equals() の比較で i1 と i3 は等しい
equals( ) メソッドはあくまでもメソッドであり、Java の言語仕様でないことに注意しなければいけません。
例えば、自分で作成したクラスで、equals( ) メソッドを使用してオブジェクトの同値性を評価する場合、equals( ) メソッドを正しく実装する必要があります。
以下のように数値を保持するクラスを作成したとします。
public class Suuti { public int value; public Suuti(int suuti) { this.value = suuti; } }
このクラスを先ほどの例に沿って実行すると、同じ値でオブジェクトを作成しても同一の内容としてみなしてくれません。
Suuti s1 = new Suuti(1);
Suuti s2 = s1;
Suuti s3 = new Suuti(1); if (s1.equals(s2)) {
System.out.println("equals() の比較で s1 と s2 は等しい");
} else {
System.out.println("equals() の比較で s1 と s2 は等しくない");
}
if (s1.equals(s3)) {
System.out.println("equals() の比較で s1 と s3 は等しい");
} else {
System.out.println("equals() の比較で s1 と s3 は等しくない");
}
プログラムの実行結果は以下のようになります。
equals() の比較で s1 と s2 は等しい equals() の比較で s1 と s3 は等しくない
equals( ) メソッドは、すべての JavaAPI (クラス)が継承する Object クラスで実装されています。
Object クラスが実装する equals( ) メソッドは参照値が同じであることを評価するため、自分で作成したクラスで値の同値性を評価したい場合は、equals( ) メソッドを実装しなければいけません。
それでは、ここで先ほどの Suuti クラスに対して、equals( ) メソッドを実装しましょう。
public class Suuti {
public int value;
public Suuti(int suuti) {
this.value = suuti;
}
public boolean equals(Object obj) {
// オブジェクトがnullでないこと
if (obj == null) {
return false;
}
// オブジェクトが同じ型であること
if (!(obj instanceof Suuti)) {
return false;
}
// 同値性を比較
return this.value == ((Suuti)obj).value;
}
}
equals( ) メソッドでは、引数で受け取ったオブジェクトが null でなく、同一の型のオブジェクトである場合にのみ値の比較をします。
この例では、数値( int )を基本データ型として保持しているので、この値( value )比較演算子で比較しています。
一般的にequals()メソッドは以下のことに注意します。
オブジェクトの比較で String を使用し = = 比較演算子で比較する場合には注意が必要です。
Java では、メモリ使用効率を最適化するために同じ値の文字列リテラルは再利用されます。
これにより、オブジェクトの比較について = = 演算子を使用した場合、誤解を招く結果となります。
同じ値のリテラルを直接代入した場合、リテラルは再利用されるため、代入されたオブジェクトは同じ参照値を持ちます。
String st1 = "a";
String st2 = "a";
if ( st1 == st2) {
System.out.println("st1 と st2 は同じです");
} else {
System.out.println("st1 と st2 は同じではありません");
}
プログラムの実行結果は以下のようになります。
st1 と st2 は同じです
同じ値のリテラルであってもオブジェクトの生成を明示的に行うと参照値は別になります。
String st1 = new String("a");
String st2 = new String("a");
if ( st1 == st2) {
System.out.println("st1 と st2 は同じです");
} else {
System.out.println("st1 と st2 は同じではありません");
}
プログラムの実行結果は以下のようになります。
st1 と st2 は同じではありません
instanceof はオブジェクトの生成元となった型を評価するための演算子です。
Instanceof では左側のオペランドに変数、右側のオペランドにクラス名(型名)を記載します。
評価結果は boolean で返されます。
また、右側のオペランドには、継承もとのスーパークラス、インタフェースや配列の指定ができます。
String st1 = "a";
String[] st2 = {"a","b"};
Object obj1 = st1;
Object obj2 = st2;
if (obj1 instanceof String) {
System.out.println("obj1 は String 型です");
}
if (st1 instanceof Object) {
System.out.println("st1 は Object を継承しています");
}
if (st1 instanceof Serializable) {
System.out.println("st1 は Serializable を継承しています");
}
if (obj2 instanceof String[]) {
System.out.println("obj2 は String 型の配列です");
}
プログラムの実行結果は以下のようになります。
obj1 は String 型です st1 は Object を継承しています st1 は Serializable を継承しています obj2 は String 型の配列です