• 締切済み

オブジェクトの参照およびハッシュコードについて

 下記のプログラムは任意のクラスMoofおよびStringクラスについてそれらのオブジェクトの参照値とハッシュコードをプリントし、さらにStringオブジェクトの参照値同士の比較をしています。 次の質問に対して分かりやすくご教示ください。 (1)Moofオブジェクトについては参照値そのものの値を出力しているようですが、Stringオブジェクトの場合はオブジェクトの値(abc)が出力されているのは何故ですか (2)参照値の構成は(クラス名+@+16進ハッシュコード)であり、オブジェクト(インスタンス)のあるアドレスを指し示すと聞きました。Stringオブジェクトは2つあってその値はabcで等しいのでハッシュコードも同じになっている訳ですが、もしハッシュコードがアドレスを示すとすると2つのオブジェクトに対してアドレスは1つとなりますが… (3)上の(2)に関連して参照値four、fiveに関するオブジェクトのハッシュコードはともに0x17862で等しいのですが、両者を==演算子で比較するとfalseとなります。 これはどうしてですか。  どなたか詳しい方、よろしくお願いします。 public class EqualsCheckX { public static void main(String[] args) { Moof one = new Moof(8); Moof two = new Moof(8); Moof three = one; int a = one.hashCode(); int b = two.hashCode(); int c = three.hashCode(); String four = new String("abc"); String five = new String("abc"); String six = four; int d = four.hashCode(); int e = five.hashCode(); int f = six.hashCode(); System.out.println("Moof " + " one : " + one + " two : " + two + " three : " + three); System.out.println("String" + " four : " + four + " five : " + five + " six : " + six); System.out.println(); System.out.println("hashCode" + " one : " + Integer.toHexString(a) + " two : " + Integer.toHexString(b) + " three : " + Integer.toHexString(c)); System.out.println("hashCode" + " four : " + Integer.toHexString(d) + " five : " + Integer.toHexString(e) + " six : " + Integer.toHexString(f)); System.out.println(); // String if (four == five) { System.out.println("String : four and five are equal"); } else { System.out.println("String : four and five are not equal"); } if (four == six) { System.out.println("String : four and six are equal"); } else { System.out.println("String : four and six are not equal"); } } } class Moof { private int moofValue; Moof(int val) { moofValue = val; } } C:\MyJava>java EqualsCheckX Moof one : Moof@1ac04e8 two : Moof@765291 three : Moof@1ac04e8 String four : abc five : abc six : abc hashCode one : 1ac04e8 two : 765291 three : 1ac04e8 hashCode four : 17862 five : 17862 six : 17862 String : four and five are not equal String : four and six are equal

みんなの回答

  • ngsvx
  • ベストアンサー率49% (157/315)
回答No.4

いくつか勘違いがあるようです。 1.System.out.println("Moof " + " one : " + one + " two : " + two + " three : " + three);を実行したときにはObejctクラスのtoString()メソッドが実行されています。 つまり、 " one : " + one.toString() + " two : " が省略されたものと同じです。 そしてMoofクラスではtoString()をオーバーライドしていないためObjectクラスのtoString()が実行されます。 toString()の役割は、そのインスタンスを文字列で表現することですが、Objectクラスでは特に文字列表現するような情報はありません。 そのため仕方なく「クラス名+@+16進ハッシュコード」を返しているだけです。 2.hashCode()というのは参照値とはなんの関係もありません。  Objectクラスでアドレスを返しているのは、たまたまであり、  アドレスを使って何かをするというのは推奨されるものではありません。 3.「一方で参照値a、bはその値を知ることができたとすれば」ということですが、本来参照値を知ることができないので、この質問は意味がありません。

KuroGin
質問者

お礼

ngsvx殿 長い間お付き合いいただきありがとうございました。 私は64歳で数年前退職して今は好きなことにできる範囲でとりくんでいます。 今から三十数年も前のことになりますが、ある化学会社でプラントの計算機制御システムの開発をしていました。 当時はプロコン(プロセスコンプューター)という種類の計算機があり言語はアセンブラがベースで優先レベルとか割り込みなどの機能がありましたが、プログラムテストのときは機械語(16進4桁)でアドレス、命令、データのすべてを処理していましたので、ハードを常に意識させられていました。 それ以来コンプューターとは縁がありませんでしたが、3年前にふと最新のプログラム言語を勉強してみようと思い立ちJavaにとりくんだ次第です。ご紹介いただきました書籍は早速購入の手配をしました。 取り留めのないことを書いてまいりましたが、重ねてお礼申し上げます。また分からないことがあったら教えてください。

  • HarukaV49
  • ベストアンサー率53% (48/89)
回答No.3

clone, equals, hashCode等のメソッドのオーバーライドの具体的な 方法は殆どのJavaの本で解説されていないと思います。 なぜならば、あまりにも有名なEffective Javaで詳しく解説されているので 恐れ多くて誰も真似ができないからだと個人的に思っています。 名著『Effective Java プログラミング言語ガイド 』を入手される ことをお勧めします。 『Effective Java プログラミング言語ガイド 』 http://www.amazon.co.jp/Effective-Java-%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E8%A8%80%E8%AA%9E%E3%82%AC%E3%82%A4%E3%83%89-Joshua-Bloch/dp/4894714361

KuroGin
質問者

お礼

HarukaV49殿 大変失礼いたしました。 回答者は一人だと思い込んでいましたので、あなたへのお礼が遅れてしまいました。  ありがとうございました。 なお、お勧めのあった書籍は発注しました。

  • ngsvx
  • ベストアンサー率49% (157/315)
回答No.2

疑問のポイントがわからないので、納得のいく回答になるかはわかりませんが。。。 Stringクラスでequalsメソッドがオーバーライドされているのはわかりますか? equals()メソッドは2つのインスタンスが等価であるか判定するものです。 String a = new String("abc"); String b = new String("abc"); a.equals(b) が等価でないと文字列の比較ができず困ってしまいます。 #1で説明した通り、equals()が等価であるのならhashCode()が同じ値を返さなければなりません。 そのため、StringクラスではhashCode()をオーバーライドして同じ値を返すようにしています。 まだ、わからないようなら、疑問のポイントを明確にして質問してください。

KuroGin
質問者

補足

再三即答いただきありがとうございます。 さらに質問をさせていただきます。 String a = new String("abc"); String b = new String("abc"): このとき、a.equals(b)はtrueなので int x = a.hashCode(); int y = b.hashCode(); において2つのオブジェクトのハッシュコードx、yは同じになる 一方で参照値a、bはその値を知ることができたとすればそれぞれ(クラス名+@+ha)、(クラス名+@+hb)であり、ハッシュコードha、hbは ha != hb になると思いますが、そもそもハッシュコードx、yとha、hbは違うものなのでしょうか。

  • ngsvx
  • ベストアンサー率49% (157/315)
回答No.1

(1)StringクラスはtoString()メソッドをオーバーライドして、文字列を返すようにしてあるからです。 (2)hashCode()がアドレスを返すのはObjectオブジェクトでの話で、Stringクラスではオーバーライドしていて、アドレスを返すわけではありません。 (3) (2)の理由によるものです。 ちなみに、hashCode()で返される値は、 ・equals()で比較した結果がtrueの場合はhashCode()は同じ値を返さなければならない。 ・hashCode()で同じ値が返っても、equals()の結果がtrueであるとは限らない。 とすることとされています。 従って、極端な例ではhashCode()は常に同じ値を返しても(どのインスタンスも1を返す等)この規約を満たすこととなります。

KuroGin
質問者

補足

ngsvx殿 早速のご回答ありがとうございました。 勉強不足のせいかいま一つはっきりしません。(2)に対する回答についてもう少し分かりやすく(具体的に)説明していただけませんでしょうか。 お忙しいところすみませんがよろしくお願いいたします。

関連するQ&A