インタビュアー:なぜ書き換えハッシュコードとequalsメソッドを?

 ほとんど顔の質問は尋ねなければなりません 

インタビューの中で主要なJava開発、依頼することが多い質問は:あなたはオーバーライドされているかhashcodeの方法を多くの候補者が直接書いた言いませんでした。あなたは、問題によって確認することができますので、多分何かが、書かれていません:あなたはHashMapのキー(としているKey)部分、何のletカスタムオブジェクトが存在しませんかそして、この時間は、彼らは自己矛盾した上に2つの質問に答え、候補者が言ってみましょう。

実際には、多くの人々は、単にので、この記事では、一般的に良いこの質問に回答する必要がありませんから、hashテーブルトーク私たちは自然にこれらの質問に対する答えを知っていることにより、データのHashMapのルールの存在について、。


 ハッシュアルゴリズムを乗り越えます 

知識のデータ構造確認するには:長さn(と仮定し10000、障害のデジタルストレージを(つまり、ArrayListにあると仮定して)テーブルの直線)を、我々は指定された番号を探しているなら、あなたは最初から通過する必要があります尾を見つけるためにトラバースします。

(ここではハッシュテーブルは純粋に概念的なデータ構造である、とJavaは何の関係もありません)私たちは、ハッシュテーブルを観察してみましょう。これは、数平均検索の近くに位置してい1たキーがデータをそこに格納し、その格納位置をハッシュ関数に関連付けられている、ハッシュテーブルであり、コストが非常に小さいです。

私たちは、関数があるハッシュを想定しますもちろん、現実には不可能簡単なハッシュ関数で、ここでは純粋に説明の便宜上、ハッシュテーブルの長さがあるリニアテーブル。私たちがしたい場合は、それに入れ、その後、我々は最初のでしょう、ハッシュ関数の計算結果があるので、我々はよインデックス番号がつけ、この位置。我々は数字を入れたい場合は同様に、ハッシュ関数計算の後に、結果がされ、それがインデックスに含まれますされ、この位置に。図に示すように、結果。x*x%511661617744

これの利点は明らかです。たとえば、私たちはから探している6、この要素は、我々は最初のハッシュ関数により算出した6インデックス位置、および、直接の1インデックス番号でそれを見つけます。

しかし、私たちは、「ハッシュ値の衝突、」この問題が発生しました。例えば、ハッシュ関数を計算し、後7および8JavaのHashMapのオブジェクトを使用するのと同じハッシュ値である持っている「鎖アドレス方式」溶液。図に示すように結果。

具体的なアプローチは、すべてのハッシュ値であるi同義語リストを作成するためのオブジェクト。我々は中に入れていると8時間、見つかった4ん場所は、それがリンクリストに新しいノードを作成し、計上されていません8我々が探している場合は同様に、8[検索、4インデックス内の数字はないが8、それは、リストダウン表情に変わります。

我々はまだ完全にハッシュ値の競合の問題を回避することはできませんが、ハッシュ関数の設計が合理的であるが、それはまだ同義語リストの長さは、合理的な範囲で制御されていることを確認することができます。理論的知識といえばランダムではありません、我々は明らかに後で理解できる重要書き換えhashCodeメソッド


 オーバーライドイコールとhashCodeメソッドへの髪のために 

私たちは、HashMapのでカスタムクラスを堆積するとき、彼らはクラス定義からのequalsとhashCodeメソッドをオーバーライドしていない、結果は我々が期待通りに同じではないだろう場合。で見てみましょう。この例。WithoutHashCode.java

前記第2二の18行、我々は定義するKeyクラスと、第1た3行は、一意のプロパティを定義しますid現在、我々は最初の最初のコメントアウト9の行equals法と16ラインhashCode方法を。

  1. 1 import java.util.HashMap;

  2. 2 class Key {

  3. 3 private Integer id;

  4. 4 public Integer getId()

  5. 5 { return id; }

  6. 6 public Key(Integer id)

  7. 7 { this.id = id; }

  8. 8 //故意先注释掉equals和hashCode方法

  9. 9 // public boolean equals(Object o) {

  10. 10 // if (o == null || !(o instanceof Key))

  11. 11 // { return false; }

  12. 12 // else

  13. 13 // { return this.getId().equals(((Key) o).getId());}

  14. 14 // }

  15. 15

  16. 16 // public int hashCode()

  17. 17 // { return id.hashCode(); }

  18. 18 }

  19. 19

  20. 20 public class WithoutHashCode {

  21. 21 public static void main(String[] args) {

  22. 22 Key k1 = new Key(1);

  23. 23 Key k2 = new Key(1);

  24. 24 HashMap<Key,String> hm = new HashMap<Key,String>();

  25. 25 hm.put(k1, "Key with id is 1");

  26. 26 System.out.println(hm.get(k2));

  27. 27 }

  28. 28 }

ではmain最初の関数2223行、我々は2定義しKeyたオブジェクトを、彼らがidしている1彼らが同じ2つのキーが同じドアを開けることができているように、。

最初に24行、我々はジェネリックでHashMapのオブジェクトを作成しました。その主要部分は保存することができるKeyオブジェクトのタイプを、オブジェクトは、String型の値の部分を格納することができます。

最初に25行、我々は合格putk1と入れて文字列hmにすると、第1に26ライン、我々は望んk2ではHashMapから値を取得するために、私たちが使いたいようなものだk1、ドアをロックするために使用し、このキーをk2ドアを開きます。これは論理的であるが、現在の結果が、26結果は我々は、行の文字列と想像が、何ではありません返しますnull

2つの理由があります。まず、hashCodeメソッドをオーバーライドしていないが第二は、equalsメソッドを書き換えることではありません

我々はHashMapのに入れたときk1の時間、それは最初に呼び出しますKeyクラスhashCodeの計算方法hash値を、次に置くk1メモリ位置によって導かれたハッシュ値に。

キーは、私たちが持っていないですKeyの定義にhashCodeする方法。ここでは、コールはまだObjectクラスのhashCodeメソッド(すべてのクラスがObjectのサブクラスです)、およびObjectクラスhashCodeメソッドの戻りhash値は、実際k1のオブジェクト内存地址(1000であると想定します)。

我々は通話に従った場合、我々は再び呼び出されますメソッド(またはリターンアドレス)後、得られたに基づいた値、それはすぐに見つけることができますhm.get(k1)hashCodek11000hashk1

しかし、私たちはここにあるコードは、我々が呼ぶとき、クラス(のような方法を計算するために定義されていない)で、実際には、値を取得したメモリアドレスを(あると仮定)。以来2つの異なるオブジェクトである、彼らは彼らで同じメモリアドレス、ではありません、これは私たちが使用できないものです、値が異なっていなければならない価値が選ぶ理由。hm.get(k2)ObjecthashCodeKeyk2hashk22000k1k2hashk2hashk1

我々は最初のとき1617hashCode注釈メソッドの後に削除するために、あなたはそれを返すでしょうid属性hashCode値、どこにk1、とk2しているid彼らのように、両方の1 hashの値が等しいです。

私たちはどのような預金修正しようk1とテイクk2アクション。デポジットk1それが基づいている値は、ここで想定しオブジェクトが対応する位置に配置されます。そして取る、それが最初に計算された時間を、(原因値にはあり、この値である)、この位置にアクセスしてください。idhash100k1k2hashk2id1100

明らかに:しかし、結果は私たちの驚きになる100数の場所がすでに持っているk1が、最初の26出力ラインが残りますnullその理由は、何が上書きされることはありませんKey、オブジェクトのequalsメソッドを。

HashMapのリンクアドレス方式の競合を処理するためには、すなわち、100番号位置は、リンクされたリストに格納されたオブジェクトが複数存在してもよいです。そのことにより、hashCodeメソッドの戻りhash値は100です。

我々が通過するときk2hashCodeまで100、時間位置番号検索あなたは入手できますかk1しかし、k1そこだけであってもよく、k2同じ持っているhash価値を、必ずしも必要ではないが、とk2等しく(k1およびk22つのキーが同じドアを開くことができない場合があります)、この時間は、我々は呼び出す必要がありKey、オブジェクトのequals2が等しいAであるかどうかを決定する方法を。

私たちは以来Keyのオブジェクトを定義しないequals方法、システムがコールする必要がありますObjectクラスのequalsメソッドを。起因するObject固有のアプローチは、二つのオブジェクトに基づいてメモリアドレスの判断に、k1そしてk2確かにそれはまだある理由である、と等しくない26ことにより、ラインまだ取得理由を。hm.get(k2)null

この問題を解決するために、我々は最初に開く必要がありますライン注釈方法を。この方法では、限りオブジェクトが2つであるようなタイプが、それらは等しく、それらは同じです。914equalsKeyid


 再び 

ので、プロジェクト以来、頻繁に使用HashMapのだったインタビューは、ほぼ確実に質問をします、あなたは、オーバーライドされています:hashCodeメソッドを?HashMapの使用しているときは、書き換えたのhashCodeequals方法を?あなたはどのように書くのですか?

最後に、再び:あなたがオブジェクトのHashMapの「キー」セクションでは、カスタムが含まれている場合は、それ自身では、このオブジェクトを使用してくださいequalshashCodeオーバーライドするメソッドObjectと同じ名前のメソッドインチ

おすすめ

転載: www.cnblogs.com/eryun/p/12150255.html