• 締切済み

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

  • 『独習JAVA』が難しい

    『独習JAVA』が難しいと感じるのですが。 私は初心者ですが、カタカナ語が多くて。。 JAVAに向いていないだけなのか、この本が 難しいのかよくわかりません。どうなのでしょう? ついでに質問です~。 独JAVAの2章の2・1「メソッドの構造」を どなたか解説していただけないでしょうか?? 読んでも全く意味が分かりません。どこが? ときかれても「どこも」わかりません泣。 戻り値?メソッド? ??? といった感じです。1章も分からなかったけど 何とか読みました。メソッドのところは何も 分からず先に進めません。。。よろしくおねがい します。。。

    • ベストアンサー
    • Java
  • javaのメソッド呼び出し

    javaで質問があります。メソッドを呼び出すとき、 クラス.メソッド(引数)だと思いますが、 「.」が2つあるものがあります。 どういったものでしょうか? あるプログラムに Code.PerComFlag.ReCom.equals(atmlogDTO.getatmComFlg()) のがありました。 また、javaの本に System.out.println(・・・) という記述もあります。 よろしくお願いします。

    • ベストアンサー
    • Java
  • オブジェクト指向

    Javaプログラミングを少し勉強し始めました。 そこで、オブジェクト指向という言葉が出てきました。 オブジェクトを作る利点というか意味はどのようなところにあるのでしょうか? 比較的簡単なプログラムなら、変数とメソッドで表示できると思うのですが・・。 ・コードが読みやすくなる ・実行速度が速くなる などの利点があるのでしょうか? なるべく分かりやすく解説してもらえればと思います。

    • ベストアンサー
    • Java
  • 配列の型判定の仕方

    メソッドの引数をObjectにして、その引数の型を判定しようとしています。 たとえば以下のような感じです。 String hoge(Object para) { if(para.equals(java.lang.Integer.class)) { return "intです"; } return "わかりません" } 上記は、int型なら判定できるメソッドですが、int[]やString[]を判定するためにはどうしたらよいのでしょうか? paraにint[]型の値が入ってきた場合、 para.equals(java.lang.Integer[].class) としてもtrueにはなりませんでした。 どうすればできるのか、ご教授いただけると幸いです。 手段がなければ、para.getClass().toString()をして出力される文字列で判定しようかと思っています。

    • ベストアンサー
    • Java
  • Javaのソースコードを教えてください!

    Javaのソースコードを教えて欲しいです コンソールに表示して3×3の○×ゲームを作ります 条件は ・メソッドを必ず使う ・〇‪✕‬ゲームをJavaのコンソール(println()やprint())を用いて作成 ・○×を書く場所は、数値を入力して対応した場所に〇や‪✕‬を出力 ・勝利判定などゲームができる所までは作成しない ・見た目なので、「この数値はここに書く というようなナビゲーション」、「実際に入力しした後の盤面」は実装するとこ ・9回入力したらゲーム終了 です

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

     下記のプログラムは任意のクラス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

  • Javaの初期化メソッドについて

    こんにちは。Javaの初心者です。 Javaの初期化メソッド(initメソッド)についてなのですが、処理を記述しても実行してくれません。 恐らく使い方が間違ってるかと思われるのですが、ネットで調べてもあまり検索結果がでてこなかったので、質問させてもらいました。 以下サンプルコード import java.lang.*; public class Test { static int a; public void init() { a = 10; } public static void main(String[] args) { System.out.println(a); } } 実行してみても、「0」と表示されるだけで、「10」と表示してくれませんでした。 どこかコードが間違えてるのでしょうか? それとも初期化メソッドはアプレット用であってアプレットで使わないと意味がないというものなのでしょうか? 因みに関係ないかと思われますが、グローバル変数は自動的に初期化される(0が代入される)ということは知っています。 ご教授の方、よろしくお願い致します。

    • ベストアンサー
    • Java
  • Javaの多態性について質問です

    Java初心者です。どなたかお力をお貸しください。 ------------------- class Animal { public void eat() { // 汎用的なコード } } class Dog extends Animal { public void eat() { // 特化したコード } public void bite() { // Dog特有のコード } } ------------------- 上記のクラスについて質問があります。 Animal obj = new Dog(); obj.bite(); このコードがコンパイルエラーになるのは何故でしょうか? コンパイラが参照型のみをチェックし、Animalクラスにbiteメソッドが 無いため、エラーを出すと参考書に書いてありました。 つまり、スーパークラス型の参照変数にサブクラスのインスタンスを格納し、 サブクラス特有のメソッドをコールできないとはどういう意図なんでしょうか? コンパイラのチェックで引っかかるのは分かったのですが、 オブジェクト指向としては、この使い方は推奨されないということでしょうか? (Animalの参照で、Dog特有のメソッドは使わない?) 実際にJavaでプログラムを組むときには、こんな使い方をしないのですか? 有知識者の方、教えて下さい。 私は、オブジェクト指向の多態性の理解が甘いため、こんな質問をしているのだと 思います。申し訳ございません。

    • ベストアンサー
    • Java
  • Javaの習得に向けたグラフィックスについて

    Javaの習得に向けて学習する場合、ひとえにオブジェクトがどういう風なものなのかを習得するということが主眼になると思います。クラス,メソッド,クラスの継承とか,クラス間での変数のスコープ(これは全言語で共通の学習)とかです。ファイル入出力、ループ、分岐なども全言語共通的なので翻訳可能であり、学習の対象ですらないもののように思えます。 しかし、グラフィカル(GUIを生成して、ブラウザで見せたりする)なところになると急激に視界不良のような印象になります。長い名前のコマンドでイベントリスナーとかフレームとかのオブジェクトとかラジオボタンをペタペタ貼り付けるとかです。それらのグラフィックスの機能というのは、Java独特のクラスとかオブジェクトの学習と関連しているのかどうかわかりにくくなる印象を持ちます。Javaの学習とあのグラフィックスは切り離して考えるのか、それともJavaの学習の結果その応用としてグラフィックス関係の処理が出てくるのか不明な感じになります。もし後者なら学習した内容に照らし合わせた機能と考えて納得させる必要がありますが、前者ならあんまり気にしないでブラックボックスとして処理するということになりそうです。Javaのグラフィックスはどのように理解して学習すればいいのでしょうか。 例えばVisual BasicなどはオブジェクトをGUI的に作ってウィンドウ上に貼り付けてその機能をコード化するということになるので、もう少しわかりやすいというか整理して(分業というか)して処理できそうですが、Javaは全部コード化するので理解しにくい印象があります。たとえばコードがあってその横にグラフィックスが示されているなら、もう少しマシなのですが。Javaの入門書では全くグラフィックスに触れないものあり、それだと通読しやすいです。グラフィックスが出てくると急激に歩みが遅くなるのですが。考え方について教えて頂きたいと思います。 よろしくお願いします。

  • JAVAソースコードの暗号化

    JAVAソースコードの暗号化 失礼致します。 カテゴリを間違えて登録してしまった為再度登録させてもらいます。 JAVAのソースコードに公開したくないロジックが含まれており、 ソースコードを暗号化したいと考えています。 もし同じようなことで悩んだ方がいらっしゃいましたら、 アドバイスいただきたいと思い書き込みします。 まず「どこまで暗号化(隠蔽)できればよいのか」という基準については、 「jadで逆コンパイルしても内部のロジックが読み取れなければよい」 と考えています。(特にディレクトリのパスが指定していますのでその部分、変数の中身等) ためしにフリーのProGuardを使用してみましたが、 クラスファイル名やメソッド名、変数名がa,b,cなどに変換されたものの、変数の中身は丸見えのままでした。 【元データの逆コンパイル】 String confFilePath = rootPath + "conf/"; String masterFile = confFilePath + subDir + "Pass.xml"; String confSubDir = confFilePath + subDir; String outputPath = rootPath + "file/" + subDir; 【ProGuardをかけて逆コンパイル】 Object obj; obj = s + "conf/"; String s2 = obj + s1 + "Pass.xml"; String s3 = obj + s1; String s4 = s + "file/" + s1; ProGuard自体、ソースコードの軽量化に使われるのが主流なようなので、仕方がないといえば仕方がないと思いますが、 どうにか読み取られないようにできないものでしょうか。 ご意見、お待ちしています。 ※次はDashOの評価版を試してみようと考えていますが、 あまりお金はかけたくないので、正規に使う見込みがありません。 ただお金をかければこんだけの暗号化はできるというのがあれば教えてもらいたいです。 何日も調べてかなり悩んでいます、、お願いします。

    • ベストアンサー
    • Java

専門家に質問してみよう