入門
私たちは、クラスセットがあり、一つのカテゴリがリストされ、Javaのコレクション(コレクション)に大別することができることを知っています。
前者のセット内の要素は、順序付けされた要素を繰り返すことができ、障害後者の要素が、要素を繰り返すことができません。
ここでは、質問を頼む:要素がそれを判断する根拠がどうあるべきか繰り返されないようにするには?
なぜのhashCode()?
重複したデータに問題を解決するために、開始開発者はメソッドを使用してはObject.equalsと考えています。
しかし、彼らはすぐに追加の各要素は、一度チェックしている場合ことを発見したときに、相対的に非常に多くのセット内の要素の数を追加した後の要素の多くは、。
これは、コレクションが今コレクションの最初の要素1001、1000個の要素を持っている場合、equalsメソッド1000年を呼び出す必要がある、です。これは明らかに、効率を大幅に軽減します。
だから、Javaはハッシュテーブルの原理を使用しています。彼は彼の名前に名前の「ハッシュアルゴリズム」の概念を提唱しているため、ハッシュ(ハッシュ)は、実際に、個人名です。
また、ハッシュ・アルゴリズムのハッシュアルゴリズムを知られているハッシュ値はまた、ハッシュコードと呼ばれ、実際にデータを直接ハッシュアルゴリズムに従って指定されたアドレスへ。
初心者が簡単に理解することができ、hashCodeメソッドは、実際には(実際にはおそらくない)オブジェクトの物理アドレスが格納されて戻ります。
それは物理的な場所に配置されると、このように、要素の新しいセットを追加する場合、この要素のhashCodeメソッドを呼び出す前に、その上に配置することができます。
この位置にある要素がない場合は、それがこの位置に直接保存することができ、我々は、任意の比較を持っていません。
あなたはすでにこの位置の要素を持っている場合、それは新しい要素と比較するのequalsメソッドを呼び出して、同じ言葉は存在しませんし、それが他のハッシュアドレスと同じではありません。
そこでここでは紛争解決の問題があります。その結果、通話の実際の数は、ほぼ2回だけ必要な、方法が大幅に削減される等しいです。
二つの方法の役割
等号()アクション:オブジェクトが他のオブジェクトと同じであるかどうかを決定するための手段と
Objectクラス)が(等号を定義されています。
パブリックブール等しい(オブジェクトobj){ リターン(この==のOBJ)。 }
明らかに、Objectクラスのネイティブコードの比較はアドレスへの参照があるが、それらの異なるニーズを満たすために書き換えの度を変化させて)などの文字列、数学、整数、ダブル、中にラッパークラスは、(すべて対等であることを思い出したする必要があります例えば、Stringクラスで:
パブリックブール等しい(anObjectオブジェクト){ (この== anObject)であれば{ trueを返します。 } (anObject instanceofの文字列){もし ストリングanotherString =(文字列)anObject。 int型のn =数えます。 IF(N == anotherString.count){ チャーV1 [] =値。 チャーV2 [] = anotherString.value。 私はint型=オフセット。 int型J = anotherString.offset。 (!N- = 0){しばらく (!V1 [I ++] = v2の[J ++])場合は falseを返します。 } trueを返します。 } } falseを返します。 }
明らかに、Stringクラス()アドレス比較は、もはやオブジェクト自体への参照ですが、Java8基本データ型に内容が、実際には、価値ある比較すること()に等しい等しくありません。
ハッシュコード()関数:識別コードに対応する異なるオブジェクトの異なるハッシュコード値への復帰。
ハッシュコードを使用する場合は()以下の3点を満たしていなければなりません。
- 常に同じ整数を返さなければならない回数のhashCodeを(呼び出し)に関係なく、オブジェクト、情報が変更されていないに等しくないのJavaアプリケーションの実行中に、オブジェクトは、比較を提供する場合。
- 等しい(オブジェクト)の方法に従って2つのオブジェクトが等しい場合は、()2つのそれぞれのハッシュコードを呼び出すと同じ結果整数を生成しなければなりません。
- 2つのオブジェクトは、対等を呼び出し(java.lang.Objectの)メソッドの結果は、それぞれのhashCode(両方を呼び出し、等しくない)は必ずしも同じではない、同じであってもよく、異なっていてもよいです。
重点
コレクションを見て、間違いなくハッシュコードを使用して大幅に、オブジェクト比較の数を減らし、検索効率を向上させます!
eqaulsとJavaオブジェクトのhashCodeメソッドは、このような要件です。
1、(同一の)オブジェクトが等しいハッシュコード(又はハッシュコード)が必要に等しいです。
図2に示すように、2つのオブジェクトが必ずしも同じでない場合、同じハッシュコード。
可能な混乱
まず、オブジェクトが等しいハッシュコード(またはハッシュコード)、およびその理由を持っている必要があります(同じ)が等しいですか?
A及びBは、同じ二つのオブジェクトであると仮定されている場合、すなわち、それらの結果は真と等しいが、計算異なるハッシュコードでありもたらす可能性があるため、それらは各ハッシュコードと同じではなく、それらはハッシュマップに格納する同じです内部配列インデックスのうちHashMapの位置が同じではありません、そして、Bはまた、HashMapの中で同じを保存する可能性が高いですが、私たちは、HashMapのは、重複した要素を格納するために許可されていないことを知っています。
2つのオブジェクトが同じハッシュコードを持っている理由第二に、彼らは必ずしも同じではありませんか?
あなたの質問は、実際に、私は個人的には2つのオブジェクトが非常に一貫性のあるいくつかの方法で持っているハッシュコードの生成をもたらす「ハッシュアルゴリズム」、によるものだと思うのhashCode異なるオブジェクトは、この結果のと同じ理由であってもよいと言っていますセックス。HashMapのハッシュコードは、2つの同一のオブジェクト、およびその文字列一緒に2つのオブジェクトを追加しますので、それが事実であるかもしれない考えると、正の指定された内部配列のハッシュコードにインデックスを配置する新しいリストを作成それは同じ性を確保できるように、当然のことながら、彼らは()に等しいを呼び出した場合、偽の値を返し、がその位置で、依然としてHashMapのハッシュコードに格納することができます。
それに追加し、この現象を記述するための特別な用語があり、我々はハッシュ衝突と呼ばれ、産業界が、ハッシュの競合を解消することができるものの、誰が頻繁にそれを見たいと思っていないことは明らかです。
練習
実際の符号化処理では、我々は多くの場合のhashCode()とequals()を書き換えることが求められます、私はまた、この質問には不可解持っていますが、今、私はすべての人に秘密を説明することができます。
HashSetの例には、我々はHashSetのは、Setインタフェースを継承し、Setインタフェースコレクションインタフェースを実装していることを知って、HashSetのは、重複した値が、また、不確実性の要素の位置を許可されていません。
だからここにあなたが2つのオブジェクトが等しいルールであるかどうかを判断するためのJavaコレクションについて教えて:
まず決意は、2つのオブジェクトが等しいハッシュコード。
それらが等しい場合には、第二段階に決定されます。
等しくない場合、2つのオブジェクトは判決の最後に、等しいと見なされていません。
二つのオブジェクト2.解析が等しい等しいあります()。
この判断も同じである場合、2つのオブジェクトが等しいと見なされます。
等しくない場合、2つのオブジェクトが等しいと見なされていません。
なぜ我々は二回、それを判断する必要がありますか?
これは、最初に決定されなくてもよいが、そうでなければ、実際の効率が大幅に大量のデータを作ると比較する場合は特に、低減されます。実際には、()が参照、等しい即ちハッシュコード()ハッシュコードを導入する前に、等号()は等しくなくてもよいので、我々は、第二の決意を限定することを添加しました。一般的には、第1の判定が可能ではないが、2番目の決意である必要がありますが、2は、好ましくは、実際の開発で書かれている、大量のデータを一度のみのequals()判決を出現判断する必要がありますその後、効率が大幅に削減されるであろう。
コード表示
パッケージ演習。
輸入はjava.util.HashSet。 パブリッククラスE1 { パブリック静的無効メイン(文字列[] args){ HashSetののHS =新しいHashSetの()。 hs.add(新しい学生(1、 "张三")); hs.add(新しい学生(2、 "李四")); hs.add(新しい学生(3、 "王麻子")); hs.add(新しい学生(1、 "张三")); 用(Objectオブジェクト:HS){ System.out.printlnは(オブジェクト)。 } } } クラスの学生{ int型NUM。 文字列の名前。 学生(int型NUM、文字列名){ this.name =名。 this.num = NUM; } パブリック文字列のtoString(){ 戻りNUM + ":" +名。 } }
結果:
なぜHashSetのは、それの同等の要素を追加し、これは、HashSetのそれの原則に反しありませんか?答えは:なし。異なるハッシュコード値を生成する場合()は、2人の新しい学生の確立に(1、「ジョー・スミス」)オブジェクトハッシュコードに従って比較される、なぜなら、HashSetのはもちろん、異なるオブジェクトとして彼を治療するために、この値が等しい場合()メソッドの戻りそうではありません。
なぜ異なるハッシュコード値を生成するのでしょうか?その理由は、比較して、()オブジェクトクラスのhashCodeを継承している、とhashCodeオブジェクトクラス()ローカルであるので、それは、私たち自身のStudentクラスはありません再自身のhashCodeを(書き込み)とequals()メソッドであります比較の方法は、アドレス(基準アドレス)オブジェクト、コースの2つの異なるオブジェクトを生成する新しい方法を使用してオブジェクトを作成し、結果をハッシュコード()2つのオブジェクトが値が同じではない返すので、HashSetのことです異なるオブジェクトとして扱います。
どのようにこの問題を解決するには?答えは:Studentクラス内のhashCode()とequals()メソッドをオーバーライドします。
パッケージ演習。 輸入はjava.util.HashSet。 パブリッククラスE1 { パブリック静的無効メイン(文字列[] args){ HashSetののHS =新しいHashSetの()。 hs.add(新しい学生(1、 "张三")); hs.add(新しい学生(2、 "李四")); hs.add(新しい学生(3、 "王麻子")); hs.add(新しい学生(1、 "张三")); 用(Objectオブジェクト:HS){ System.out.printlnは(オブジェクト)。 } } } クラスの学生{ int型NUM。 文字列の名前。 学生(int型NUM、文字列名){ this.name =名。 this.num = NUM; } @Override 公共int型のハッシュコード(){ 31 =最終INTプライム。 int型の結果= 1; 結果=プライム*結果+((名前== nullの)0:?name.hashCode()); 結果=プライム*結果+ NUM。 結果を返します。 } @Override パブリックブール等しい(オブジェクトobj){ (この== OBJ)場合に trueを返します。 (OBJ == nullの)があれば falseを返します。 もし(のgetClass()= obj.getClass()!) falseを返します。 (学生)=他の学生OBJ。 もし(名前== NULL){ (other.name = nullが!)場合は falseを返します。 }他(name.equals(other.name)!)場合は falseを返します。 (NUM = other.numが!)場合は falseを返します。 trueを返します。 } パブリック文字列のtoString(){ num戻り+ ":" +名。 } }
業績
あなたは(メソッドがハッシュコードを書き換えるためによると、新しい学生(1、「ジョー・スミス」)への2つのコールが、我々は、オブジェクトのハッシュコードを取得した場合でも、メソッドを書き換えるよると、反復要素の問題が解消されている見ることができます)ハッシュコードは、我々が決定することができ、同じ、もちろん、対等に応じて()メソッドは同じなので、あなたがルックアップするための要素を繰り返すようコレクションのHashSetに追加するときにする必要があり得ます。
ただ、書き換えがショートカットキーで行われ、私たちはノックする手が、必要ではないので、多くを書くことができます。
手には、コードを書き換えるノック:
公共int型のhashCode(){ num戻り* name.hashCode(); } パブリックブール等しい(オブジェクトo){ 学生S =(学生)O。 NUM == s.num && name.equals(s.name)を返します。 }
総括します
- 焦点は、ハッシュコードがちょうど(効率のために)技術的な要件を書き換えるイコールです。
- なぜオーバーライドは何に等しいですか?Javaのコレクションフレームワークは、2つのオブジェクトが等しいイコールであるかどうかによって判断されるからです。
- 多くの場合、関連するオブジェクトのコレクションを格納するために使用休止状態に設定し、セットのセットを繰り返すように許可されていません。あなたがHashSetのコレクションに要素を追加すると、実際には、限りリライトが等しくなるよう()このいずれかが行います。しかし、HashSetの要素は比較的長い時間、または書き換えのequals()メソッドは、我々は唯一の判断は、効率が非常に低くなります()equalsメソッドを比較するときに複雑なので、ハッシュコードの導入()このメソッドは、増加するだけです効率は、これは非常に必要です。
hashCode()書き込みの場合:
ハッシュコードを公開しINT(){ リターン1; //無効等価ハッシュコード }
この効果は、各オブジェクトはハッシュコードを返したため、ハッシュコードを比較する際には、決定できないことである各比較はもちろんの意志()メソッドは、後に繰り返しに等しいか否かを判定するために通過しなければならない、1であります原因効率が大幅に削減されます。
参考記事: