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

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

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

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

Q&A

解決済

3回答

985閲覧

hashCode()のオーバーライドで結果が変わる

etrisotoko777

総合スコア25

Java

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

0グッド

0クリップ

投稿2020/03/11 14:37

編集2020/03/16 15:32

HashSetコレクションに、
nameフィールドを"ケント"と設定したHero型インスタンスh1を格納しました。
次に、h1に新しくHero型インスタンス、nameフィールド"ケント"を生成しました。

java

1Set<Hero> Member = new HashSet<Hero>(); 2 Hero h1 = new Hero(); 3 h1.name = "ケント"; 4 5 list.add(h1); 6 System.out.println("要素数=" + list.size()); 7 8 h1 = new Hero(); 9 h1.name = "ケント"; 10 list.remove(h1); 11 System.out.println("要素数=" + list.size());

その後、h1をremoveメソッドで取り除いたのですが、
要素数は、removeメソッドを取り除く前と同じでした。

要素数の除去はhashcode()をオーバーライドすれば解決できたのですが、
今回格納した要素"h1"は、インスタンス変数名が同じで、
ハッシュ値は変わらないと思うのです。

オーバーライドの内容

java

1@Override 2 public int hashCode() { 3 final int prime = 31; 4 int result = 1; 5 result = prime * result + ((name == null) ? 0 : name.hashCode()); 6 return result;

hashCode()メソッドのオーバーライドの有無で結果が変わるのはなぜでしょうか?

##追記】
手元の参考書には
ハッシュ値の条件として
・同じ(等価)インスタンスからは、必ず同じハッシュ値が得られること
・異なるインスタンスからは、なるべくことなるハッシュ値が得られること

と書かれていました。
変数名ではなく、参照先のアドレスからハッシュ値を生成しているのでしょうか。
そう考えるとオーバーライドによって結果が変わることに納得できます。

発生している問題・エラーメッセージ

要素数=1 要素数=1

該当のソースコード

java

1import java.util.HashSet; 2import java.util.Set; 3 4class Hero { 5 public String name; 6 7 @Override 8 public boolean equals(Object obj) { 9 if (this == obj) 10 return true; 11 if (obj == null) 12 return false; 13 if (getClass() != obj.getClass()) 14 return false; 15 Hero other = (Hero) obj; 16 if (name == null) { 17 if (other.name != null) 18 return false; 19 } else if (!name.equals(other.name)) 20 return false; 21 return true; 22 } 23} 24 25public class TryOverRideSet { 26 27 public static void main(String[] args) { 28 Set<Hero> Member = new HashSet<Hero>(); 29 Hero h1 = new Hero(); 30 h1.name = "ケント"; 31 32 list.add(h1); 33 System.out.println("要素数=" + list.size()); 34 35 h1 = new Hero(); 36 h1.name = "ケント"; 37 list.remove(h1); 38 System.out.println("要素数=" + list.size()); 39 } 40 41}

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

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

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

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

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

guest

回答3

0

ベストアンサー

まずそもそも、オブジェクトを引数にとるremoveメソッドは、
引数オブジェクトと等しいものがあれば、そのうち一つを削除する
というものです。等しいものが無ければ何もしません。そのため、

その後、h1をremoveメソッドで取り除いたのですが、

要素数は、removeメソッドを取り除く前と同じでした。

これはそもそも取り除けていないということを言っておきます。

ではなぜ、hashCodeのオーバーライドの有無で結果が変わったかの話をします。
これはこのコードで使っているHashSetの内部の仕組みが関係しています。
HashSetは、その内部での要素の格納場所を、その要素のhashCodeの返り値をもとに決定しています。
電話帳なんかで名前の頭文字で分類するような感じです。
要素を検索する場合も、目的のオブジェクトのhashCodeをもとにして探す場所を決定します。
等しいものはhashCodeも同じというルールが守られている限り、そこ以外に目的のものが存在する可能性がないからです。

hashCodeをオーバーライドしていない場合、コンピュータが勝手に割り振った値がhashCodeになります。この場合、等しいものに等しいhashCodeが割り当てられるとは限らないため、目的のものを探せなくなります。だからremoveで削除要素を探すことができず、取り除けないという結果になります。

投稿2020/03/12 19:01

swordone

総合スコア20651

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

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

etrisotoko777

2020/03/15 15:31

回答ありがとうございました。 質問時にはアドレスをハッシュすることを分かっていませんでした。 hashCode()をオーバーライドする必要性も理解できました。ありがとうございます。
swordone

2020/03/15 18:34

あと紛らわしいので、Set型の変数の名前をlistにするのはやめましょう。
etrisotoko777

2020/03/16 15:30

了解です。ありがとうございます
guest

0

念のため・・・
変数の値と変数名を混同していないですよね?
※混同してないけど、思っていることと違う表現をしていませんか?

h1.name = "ケント";

と、してるので変数名をケントだと勘違いしてないですよね?
変数名はnameのほうです。
変数の値、変数値がケントです。

もし、変数名が同じならハッシュ値が同じだと思い込んでいるなら

h1.name = "ケント";
h1.name = "サンドラ";

が、同じハッシュ値を返すと思っていたってわけじゃないですよね?
※サンプルが同じ値ケントを設定していたので。

変数名ではなく、参照先のアドレスからハッシュ値を生成しているのでしょうか。

How does the default hashCode() work?

参照先のアドレスが、h1.nameのことだと思っていたら違います。
h1のアドレスからハッシュ値を出しています。

Note that the identity hashCode() implementation is dependant on the JVM.

とのことです。

投稿2020/03/12 01:53

編集2020/03/12 02:15
momon-ga

総合スコア4820

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

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

etrisotoko777

2020/03/15 15:29

回答ありがとうございました。 ご指摘いただいて、あらためてインスタンスと変数名、値の理解を見直すきっかけになりました。
guest

0

hashCode に変数(名)は関係ありません. というより, インスタンスに変数(名)は関係ありません.

投稿2020/03/11 14:56

jimbe

総合スコア12648

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

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

etrisotoko777

2020/03/11 15:01

なるほどです。ありがとうございます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問