質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

4回答

6735閲覧

hashCodeメソッドの中で行われている処理がイマイチ理解できない

former_neet_cat

総合スコア46

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

2クリップ

投稿2018/03/11 15:22

###何をしているか理解したいです。
参考書を読み進めていると、コードの中で何の処理をしているのかイマイチ理解できない箇所が出てきました。

参考書の内容は、以下のコードを実装し、オブジェクトが同じ場合は hashCodeメソッドも同じ値を返すように修正する、というものです。

java

1@Override 2 public int hashCode() { 3 final int prime = 31; //なぜ31なのか? 4 int result = 1;  //resultに1を設定 5 result = prime * result + employeeNo; // resultに31と1を掛けてemployeeNoを足している?? 6 result = prime * result + ((employeeName == null) ? 0 : employeeName.hashCode()); //?? 何をしているのかよくわからない。 7 return result; // 結果を返している・・・ 8 }

全体のソースコード

java

1public class Employee { 2 3 private int employeeNo; 4 private String employeeName; 5 6 public Employee(int employeeNo, String employeeName) { 7 this.employeeNo = employeeNo; 8 this.employeeName = employeeName; 9 } 10 11 @Override 12 public boolean equals(Object obj) { 13 if (this == obj) { 14 return true; 15 } 16 if (obj == null) { 17 return false; 18 } 19 20 if (getClass() != obj.getClass()) { 21 return false; 22 } 23 24 Employee other = (Employee)obj; 25 if (this.employeeNo != other.employeeNo) { 26 return false; 27 } 28 if (employeeName == null) { 29 if (this.employeeName != null) { 30 return false; 31 } 32 33 } 34 else if (!employeeName.equals(other.employeeName)) { 35 return false; 36 } 37 38 return true; 39 40 } 41 42 @Override 43 public int hashCode() { 44 final int prime = 31; 45 int result = 1; 46 result = prime * result + employeeNo; 47 result = prime * result + ((employeeName == null) ? 0 : employeeName.hashCode()); 48 return result; 49 } 50 51 52} 53

java

1import java.util.HashSet; 2import java.util.Set; 3 4public class Eaction { 5 6 public static void main(String...arge) { 7 8 Employee employee1 = new Employee(1 , "Mr.Yamada"); 9 Employee employee2 = new Employee(1 , "Mr.Yamada"); 10 11 Set<Employee> employees = new HashSet<>(); 12 employees.add(employee1); 13 employees.add(employee2); 14 15 System.out.println(employees.size()); 16 } 17}

補足情報(FW/ツールのバージョンなど)

eclipse使用

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

hashCodeの実装方法が気になったので、回答します。

  1. JDK1.7以降ならjava.util.Objects#hashがhashCodeを実装する時に使用できます。

  2. ハッシュキーのインプレース変更をさけるためにhashCodeの計算に使用したフィールドはfinalで宣言してくださいな。


2018/03/12 追記

equalsメソッドのthis.employeeNameの判定はother.employeeNameを見るべきところを見ていないのでequalsメソッドに不具合があります。

Java

1 if (employeeName == null) { 2 if (this.employeeName != null) { 3 return false; 4 } 5 6 }

equalsメソッドをjava.util.Objects#deepEqualsを使った実装に変更しました。

ご参考まで。

Java

1import java.util.Objects; 2 3public class Employee { 4 5 private final int employeeNo; 6 private final String employeeName; 7 8 public Employee(int employeeNo, String employeeName) { 9 this.employeeNo = employeeNo; 10 this.employeeName = employeeName; 11 } 12 13 @Override 14 public boolean equals(Object obj) { 15 if (this == obj) { 16 return true; 17 } 18 // 言語仕様にてinstanceof演算子は値が nullの時はfalseを返す。 19 if (!(obj instanceof Employee)) { 20 return false; 21 } 22 Employee other = (Employee) obj; 23 if (!Objects.deepEquals(this.employeeNo, other.employeeNo)) { 24 return false; 25 } 26 return Objects.deepEquals(this.employeeName, other.employeeName); 27 } 28 29 @Override 30 public int hashCode() { 31 return Objects.hash(employeeNo, employeeName); 32 } 33} 34

投稿2018/03/11 18:34

編集2018/03/12 13:30
umyu

総合スコア5846

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

former_neet_cat

2018/03/13 04:41

追記ありがとうございます。 今後の参考にするために、参考書に書きました。 本当に助かります!
guest

0

31の理由か心当たりがあるのは

31(2^5-1)自身が素数かつ 2^n-1 の要素のため他の数値で割れない数値だからかと思われる。

まあほかの数値の場合もあるが・・・

投稿2018/03/11 15:56

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

former_neet_cat

2018/03/11 17:08

なるほど、教えていただきありがとうございます! 気になって、自身が素数かつ2^n-1 の要素などのキーワードで調べていくと以下のサイトで、同じようなことを言っているのを発見できました。 あらてめて、教えていただき感謝します。 http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=9750&forum=12
退会済みユーザー

退会済みユーザー

2018/03/11 21:59

べき乗表記の揺れで同じ意味かな
退会済みユーザー

退会済みユーザー

2018/03/11 22:05

あwそうそう ※ Java内 で 2^n とすると XOR 扱いになるから注意が必要
guest

0

前回の質問でHashSetを扱いました。これはSetの実装クラスの1つです。
Setは前回の回答で少し触れましたが、集合を扱うものです。主にある要素がその集合に入っているかどうかを判定します。
しかし、この「入っているかどうか」の判定が問題です。Listや配列のような扱い方をすると、いちいち先頭から順次同じものかどうかを判定していくことになり、集合が持つ要素が多くなればなるほど、それに比例して探すべき範囲が大きくなるため、時間がかかります。

この判定を一定時間で済ませるための方法が次のようになります。
集合の要素の管理は例えば配列を使うのですが、この時に格納する場所を決める際にhashCodeを使います。
hashCodeはObjectクラスで、equalsで等しいと判定されるオブジェクトからは同じ値が得られるようにと規定されています。この値を、例えばある整数で割った余りなどで配列の中での格納場所を決めれば、等しいオブジェクトが存在しうる場所が限定されます。
もちろん計算の結果同じ値が得られる場合がありますが、その場合は同じ場所に配列のように並べるなどの方法がとられることになりますが、すべてを検索し比較する方法よりも判定が速くなりやすいです。

この特性上、hashCode()は異なるオブジェクトからは異なる値が得られたほうが、異なる場所に格納されやすくなり、検索性能が良くなります(※)。その計算はそうなるように、つまり内容が異なるオブジェクトなら異なる値にしやすくなるような計算だと思ってください。「なぜそうなるのか」については私もわかりませんが、先人たちの知恵ということでしょう。

(※)hashCodeは「等しいオブジェクトからは等しい値」と決められているが、逆は必ずしも成立しなくていてもいい。
つまり、異なるオブジェクトから必ずしも異なる値が得られる必要はない。
まあ、intで表せる値が高々2^32通りなので、それより多くのインスタンスの種類が存在するならどんなにばらけるように計算しても必ず値が重複する組があることになる。

投稿2018/03/11 15:54

swordone

総合スコア20651

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/03/11 16:16

やたらと1ページ毎と思われるペースで質問者さんが質問してるから気になって本をしらべたら「JAVA本格入門は2冊目以降用だった」から別の本も進めるのも視野にいれないとならないきがしてきた
former_neet_cat

2018/03/11 17:12

解りやすい解説ありがとうございます! いつも教えていただき感謝しています。 ・・・もうすでに別の本を・・・げふん、げふん・・・
guest

0

ベストアンサー

簡単に言うと、オブジェクトのHash値をとってるような感じになります。

Java

1@Override 2 public int hashCode() { 3 final int prime = 31; // prime つまり素数であればなんでもよい 4 int result = 1;  // どんな数字でも問題ないです。あまり大きすぎるとオーバーフローします。 5 /* 6 * employeeNoを足すことでオブジェクトでの一意の値を得られる 7 */ 8 result = prime * result + employeeNo; 9 /* 10 * employeeNameのHash値を足すことでオブジェクトでの一意の値を得られる 11 * (employeeName == null) ? 0 : employeeName.hashCode() は三項演算子です。 12 * employeeName が null ならば 0 を null でないならば employeeName の Hash値を足します 13 */ 14 result = prime * result + ((employeeName == null) ? 0 : employeeName.hashCode()); 15 return result; 16 }

2つのObjectを考えます

Java

1Employee employee1 = new Employee(1 , "Mr.Yamada"); 2Employee employee2 = new Employee(1 , "Mr.Yamada");

この場合、employeeNo と employeeName がそれぞれ同じなのでhashCodeは同じ値を返します。

しかし

Java

1Employee employee1 = new Employee(1 , "Mr.Yamada"); 2Employee employee2 = new Employee(2 , "Mr.Yamada");

となった場合、employeeNo が異なるため hashCodeは異なります。

これを比較することで、オブジェクトが同じかどうかを見ているのだと思われます。

投稿2018/03/11 15:36

black_sleepman

総合スコア220

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

former_neet_cat

2018/03/11 15:51

丁寧で解りやすい解説ありがとうございます! 非常に助かりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問