• 締切済み

Javaのハッシュコードについて

SunJava2認定ガイドでJavaを勉強している初心者ですが、「オブジェクトとコレクション」を説明した章(第7章)に、 ・2つのオブジェクトがequals()メソッドで等しいと判定された場合、 両者のハッシュコード値は同じでなければならない ・2つのオブジェクトを等しいと見なすためには、両者のハッシュコー ドも等しくなければならない という記述がありますが、この2つのオブジェクトのハッシュコードというのは2つのオブジェクトを指すそれぞれの参照変数であると理解していいのでしょうか? … もしそうであるなら、2つのオブジェクトが等しいという意味は、2つのオブジェクトは同一であるということを意味することになるのでしょうか  どなたかご教示ください

みんなの回答

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.2

> 参考書には参照変数の値で、@の次の16進数がhashcodeとあります。 ああちょっと事情がわかってきました。 メソッドのhashCode()というのは各クラスごとに決めておかなければなりません。 例示されているMoofというクラスは何のクラスからも継承していませんが、 動作から見るとObjectクラスのhashCode()の定義が使われているようです。 Object (Java 2 プラットフォーム SE v1.4.0) http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/api/java/lang/Object.html public int hashCode() できる限り、Object クラスで定義される hashCode メソッドは、異なるオブジェクトについては異なる整数値を返します。通常、これはオブジェクトの内部アドレスを整数値に変換する形で実装されますが、そのような実装テクニックは JavaTM プログラミング言語では不要です。 そして > System.out.println("one = " + one + " two = " + two + " Three = " + three); このように記述した場合各クラスのオブジェクト(ここではone, two, three) はクラスが持ってるべきメソッド toStringを使って文字列化されます。 Object (Java 2 プラットフォーム SE v1.4.0) http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/api/java/lang/Object.html#toString() Object クラスの toString メソッドは、オブジェクトの派生元のクラス名、アットマーク (@)、およびオブジェクトのハッシュコードの符号なし 16 進表現から構成される文字列を返します。つまり、このメソッドは次の値と等しい文字列を返します。 getClass().getName() + '@' + Integer.toHexString(hashCode()) で、先に書いたようにMoofクラスでのhashCode()の値の計算方法はObjectと同じ、 つまりオブジェクトのアドレスが使われると思われます。 > Moof one = new Moof(8); > Moof two = new Moof(8); > Moof three = one; Javaでは、よくあるプログラミング言語の解説書での変数の説明にあるような「箱モデル」 は基本的に使えません。 Javaでは、変数の実体が置かれている場所を指し示す「ラベル」である程度に考えればよいと思います。 で、上記の例だと、one と two は別々に作っていますので、別の実体であり アドレスも違うということになります。 one と three は one = three という代入により、「ラベル」が同じ場所を指し示すようになります。 ですので、 > one = Moof@1ac04e8 two = Moof@765291 Three = Moof@1ac04e8 同じ実体である oneとthreeのハッシュ値もまた等しくなるというわけです。 > one and two are not equal > one and three are equal これですが、 Moofクラスでは自前の equals()メソッドを定義していないので、Objectクラスのそれと 同じ定義になると思われます。 Objectクラスのeqals()メソッドは Object (Java 2 プラットフォーム SE v1.4.0) http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/api/java/lang/Object.html#equals(java.lang.Object) Object クラスの equals メソッドは、もっとも比較しやすいオブジェクトの同値関係を実装します。つまり、すべての参照値 x と y について、このメソッドは x と y が同じオブジェクトを参照する (x==y が true) 場合にだけ true を返します。 ですので、 one.moofValue と two.moofValueが整数の値として同じであっても、oneというオブジェクトと twoというオブジェクトは実体が別のものなので等しくないという判定がされているというわけです。 もしmoofValueが同じであったらequals()では同じであるとみなして欲しいのなら、 equals()(とそれに伴ってhashCode())を自分で定義してやらなければなりません。 といった説明でどうでしょうか?

KuroGin
質問者

お礼

お忙しいところをお付き合いいただいてありがとうございました。 ご教示いただいたことをまとめると、やはり次のようになると思えるのですが…  Object クラスのequals() メソッドを使って2つのオブジェクトを 比較した結果、true が返された場合は、2つのオブジェクトは同一である。オブジェクトの実体は1つであり、その内容は等しく、さらにhashcode も当然等しくなる。… 2つの参照変数が同一のオブジェクトを指している。  オーバーライド(String クラスやラッパークラスと同じように)したequals() メソッドを定義して2つのオブジェクトを比較した結果がtrue になった場合、その内容は等しいが、一般的にそのhashcode は異なる。… この場合、hashCode() メソッドもオーバーライドしていればhashcode が等しくなるように処理してくれるんですかね? … もう一つすっきりしないので、さらに調査してみます。  sakusaker7 さんへ           KuroGin より        

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.1

ハッシュというプログラミングの技法はご存知ですか? > この2つのオブジェクトのハッシュコードというのは > 2つのオブジェクトを指すそれぞれの参照変数であると理解していいのでしょうか? 残念ながら違います。 オブジェクトの種類によって求め方は違うのですが、 例えば変数が文字列型であった場合には その中身("abc..."とか)を一文字ずつ ある計算式に放り込んで求まった値です。 http://www.cs.dm.u-tokai.ac.jp/~kikn/Java/docs/ja/api/java/lang/String.html から hashCode public int hashCode() この文字列のハッシュコードを返します。String オブジェクトのハッシュコードは、int 演算を使用して次のようにして計算されます。 s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] s[i] は文字列の i 番目の文字、n は文字列の長さ、^ はべき乗を示します。空の文字列のハッシュ値は 0 です。 戻り値: このオブジェクトのハッシュコード値 二つの文字列オブジェクトが同じものを指していれば同じなのは当然ですが、 違う実体でもその内容が同じであれば、ハッシュコードは常に等しくなります。 逆は必ずしも真ではないのですが。 文字列の場合は上記のような計算をしますが、 オブジェクトの型によって色々計算方法が決まっています。 詳しくは各オブジェクト型のhashCode()の解説を参照してください。 ところで技術者向けのところで訊いたほうが 回答が得られやすかったと思いますがなぜここで?

KuroGin
質問者

補足

早速ご回答いただきありがとうございました。 ハッシュコードについてもっと勉強してから質問すればよかったようです。 ただし、何故このような質問をしたかの理由を次に示します。 ご面倒でしょうが、私のかん違いした点についてご指摘ください。 参考書には参照変数の値で、@の次の16進数がhashcodeとあります。 public class EqualsTest { public static void main(String[] args) { Moof one = new Moof(8); Moof two = new Moof(8); Moof three = one; System.out.println("one = " + one + " two = " + two + " Three = " + three); if (one.equals(two)) { System.out.println("one and two are equal"); } else { System.out.println("one and two are not equal"); } if (one.equals(three)) { System.out.println("one and three are equal"); } else { System.out.println("one and three are not equal"); } } } class Moof { private int moofValue; Moof(int val) { moofValue = val; } } C:\MyJava>java EqualsTest one = Moof@1ac04e8 two = Moof@765291 Three = Moof@1ac04e8 one and two are not equal one and three are equal

関連するQ&A