原則とhashCodeのハッシュアルゴリズム深い理解

Javaのコレクション2種類があり、1はリストで、1が設定されています。リスト内の要素は、要素を繰り返すことができる、順序付けられています。無秩序な要素を設定しますが、要素を繰り返すことはできません。二つの要素がどのようなそれに応じて判断する必要がある場合要素が繰り返されないことを確認するには、繰り返し?Object.equals法による。しかし、それぞれの追加要素は、一度確認する場合は、ときに比較的非常に多くのセット内の要素の数を追加した後の要素の多くは、。コレクションは、コレクション1000個の要素は、最初の1001個の要素を持っている言い換えれば、equalsメソッド1000年を呼び出す必要があります。これは明らかに、効率を大幅に軽減します。だから、Javaは、ハッシュテーブルの原理を使用しています。
セット受光素子を参照するために、オブジェクトのハッシュコードのメモリアドレスに基づいて計算される場合には、インターバルに属し、この間隔equeals方法で呼び出した場合。【特記事項】また、ことに留意すべきである:ときに、同じハッシュコード値は、ときに、2つのオブジェクト、HashSetのオブジェクトが同じ場所に保存されますが、それらがfalseを返すと等しくされているので、実際にこの位置はもっとを保存するチェーン構造を使用してオブジェクト。
      
上記の方法は、効率を改善し。しかし、問題に直面している:2つのオブジェクトが等しい場合は等しいが、ない範囲で、ハッシュコードの値がメモリアドレスを上書きする前に計算されているので、そう、と考えられる別のオブジェクトを比較する機会はありません。:だからeqaulsとhashCodeメソッドのJavaは、このような要件である
2つのオブジェクトが同じであれば、その後、彼らのhashCode値が同じでなければなりません1。また私たちは、equalsメソッドを書き換えるメンバ変数やクラスへのhashCode値がそれにリンクされていることを意味hashCodeメソッドをオーバーライドしてください告げ、同じオブジェクト- >同じメンバ変数- >ハッシュコード値必ずしも同じ。
2ハッシュコード二つの同一のオブジェクトならば、それらは必ずしも同じではない、ここでの目的は、同じ方法eqauls比較を指します。

?************************ //blog.csdn.net/jiangwei0910410003/article/details/22739953ブログます:http:その後、コンテンツが再生が行われます*********************************************

具体的な例では、次の見:RectObjectオブジェクト:

パッケージcom.weijia.demo。

パブリッククラスRectObject {
公共のint X。
公共のint型のy;
公共RectObject(int型のx、int型のY){
this.x = xと;
this.y = Y。
}
@Override
公共int型のハッシュコード(){
31 =最終INTプライム。
int型の結果= 1;
結果=プライム*結果+ X。
結果=プライム*結果+ Y;
結果を返します。
}
@Override
パブリックブール等しい(オブジェクトobj){
(この== OBJ)場合に
trueを返します。
(OBJ == nullの)があれば
falseを返します。
もし(のgetClass()= obj.getClass()!)
falseを返します。
最終RectObject他=(RectObject)OBJ。
(X = other.x!)であれば{
falseを返します。
}
{IF(Y = other.y!)
偽に戻る;
}
trueに戻り;
}
}
。1
2
3
4
5
6
7
8
9
10
11
12である
13がある
14
15
16
17
18れている
。19
20は、
21である
22である
23である
24
25
26である
27
28
29
30
31は、
32
33である
34である
35は
、我々が書き換え親クラス・オブジェクトが等しく、hashCodeメソッドは、等しく、hashCodeメソッドは、その値がある場合、2 RectObjectオブジェクトxは、yの値が等しいハッシュコード等しいかどうかを確認するために、つつ戻り等しいですそれは本当であり、
次はテストコードです:
パッケージcom.weijia.demo。
インポートとはjava.util.HashSet;
publicクラスデモ{
パブリック静的無効メイン(文字列[] args){
SET =新しい新しいHashSetのHashSetの<RectObject> <RectObject>();
RectObject新しい新しいRectObject R1 =(3,3);
RectObject R2 = RectObject新しい新しい(5、5);
RectObject新しい新しいRectObject R3 =(3,3);
set.add(R1);
set.add(R2);
set.add(R3);
set.add(R1)
のSystem.out .println( "サイズ" + set.sizeは());
}
}
。1
2
3
4
5
6
7
8
9
10
11
12は
13である
14
15
我々はHashSetの、コレクションの設定された印刷サイズ、結果を4つのオブジェクトに堆積しましたそれはどのくらいですか?業績:サイズ:2
2なぜそれがありますか?我々は限りRectObjectオブジェクトX、Y属性値が等しい第1の比較ハッシュコード値は、R1とR2のオブジェクトをxはそれでは彼のハッシュコード値は、等しいように、ハッシュコードメソッドRectObjectクラスを上書きするので、これは、非常に簡単ですYが同じでないので、R2オブジェクトがに置くことができるように、ハッシュコードの範囲の属性値が、XがR3オブジェクト、同じプロパティ値とプロパティ値のY R1オブジェクト、ハッシュコードには、比較R1の今回等しいですそして、equalsメソッドのR3に、R1ので彼もxの2は、yの値は、同じであるため、R3は同じに入り、最終的にR1を追加することはできませんので、R3のオブジェクトは、同じであるなしに設定、それに追加がされていますこれら二つのオブジェクトR1とR2の一組だけ

ここでは、ハッシュコードメソッドは、ObjectオブジェクトでhashCodeメソッドをオーバーライドしないコメントをオブジェクトコード実行RectObject:
実行結果:サイズ:3
この結果、非常に単純な、最初の決定のhashCode R1とR2の対象オブジェクトです、 hashCodeメソッドオブジェクトは、オブジェクトの変換結果がローカルメモリアドレスで返すので、オブジェクトのハッシュコード異なるインスタンスではなく、同じR3とR1のハッシュコードが等しくないとしても同じであるが、== R1、R1、最終セット専用のコレクションR1、R2、R3の3つのオブジェクト、サイズは3

レッツ内容が虚偽のコメントの方法RectObjectオブジェクト、直接リターンに等しく、コメントはありませんhashCodeメソッド、コード実行:
実行結果:サイズ:3は、この結果は、我々はやや予想外分析している:
まず、R1とR2を、ハッシュコードオブジェクトの比較、R2に設定に等しくなく、equalsメソッドは、常にR1とR3に、falseを返すので、次に、R3、R1を見て、次に、それらの二つの方法に等しい比較、R3が等しいhashCodeメソッドを比較します等しいため、比較方法に等しいセットにR3、ルックR4は、R1及びR4は、比較的等しいのhashCodeを見つけたので、等しくない、R2とR3言うまでもないが、彼らはhashCodeを2つです、と言って、等しくありません4なぜそれが3になり、R 1及びR 4は同じではないので、同一のR2およびR4は、また、R3不等であり、R4は、結果のサイズでなければならない、コレクションセットに配置することができるようにR4は、等しくない場合、falseを返します?
我々はHashSetのソースを参照してくださいする必要があり、この時間は、ここではHashSetの中にaddメソッドのソースコードは次のとおりです。

/ **
*それが存在しない場合、このセットに指定された要素を追加します。
場合*より正式に、このセットに指定された要素の<tt> E </ TT>を追加し
、このセットは、どの要素の<tt> E2 </ tt>になるように含まれていません*
* <TT>(E == nullの?E2 == nullのを:e.equals(E2))</ TT>。
このセットがすでに要素が含まれている場合*、呼び出しはセットを残し
変わらず*との<tt>偽</ tt>を返します。
*
* @param電子要素は、このセットに追加する
* @returnの<tt>真</ tt>をこのセットが既に含まれていなかった場合は、指定
*要素
* /
パブリックブールの追加(E電子){
リターンmap.put(E本)== NULL。









9
10
11
12
13
14
15
可以看到其实HashSetの是基于HashMapの实现的我们这里、我们在点击のHashMap的に置く方法、源码如下:
/ **
*このマップで指定されたキーに指定された値を関連付け。
マップが以前にこのキーのマッピングを保持していた場合*、古い
*値が置き換えられます。
*
指定された値が関連付けられる* @paramキーのキー
指定されたキーに関連付けられる* @param値値
<TT>キー</ TT>に関連付けられた以前の値@return *、または
* <TT>ヌル</ TT>の<tt>キー</ TT>のマッピングがなかった場合。
*(A <TT> NULL </ tt>に戻り、マップがあることを示すことができる
*以前に関連付けられている<TT> NULL </ TT>と<

パブリックVプット(Kキー、V値){
(キー==ヌル)場合には、
putForNullKey(値)を返します。
int型のハッシュ=ハッシュ(キー);
int型I = indexFor(ハッシュ、table.length)。
{(!; E =ヌルE = e.nextエントリ<K、V> E =テーブル[i])とするための
オブジェクト・K。
IF(e.hash ==ハッシュ&&((K = e.key)==キー|| key.equals(K))){
V OLDVALUE = e.value。
e.value =値。
e.recordAccess(この);
OLDVALUEを返します。
}
}

ModCount ++;
addEntry(ハッシュ、キー、値、I);
戻りNULL;
}
。1
2
3
4
5
6
7
8
9
10
11
12である
13である
14
15
16
17
18である
。19
20は、
21である
22である
23である
24
25
26である
27
28
29
30
31であり、
私たちの主な、決意条件場合に見える
最初のための動作の、方法に等しく等しい、次にスキップ、等しくない、同じハッシュコードは、再び2つのオブジェクトが同じであるか、または二つのオブジェクトと比較するかどうかを決定する、または最後の1は、r1に入れていないので、それほど長いものを設定することができますよう、私たちはそれを説明することができる場所、実際には、コレクションのサイズは、3を超えている、それは本当のR1 == r1のを返し、そうになりません。 。だから、コレクションのサイズは、我々はhashCodeメソッドを設定している場合は常に、このコレクションは4で、falseを返し、3です。

最後に、我々はメモリリークの斜視のhashCode原因で問題を見て:コードを見て:

パッケージcom.weijia.demo。
輸入はjava.util.HashSet。
パブリッククラスデモ{
パブリック静的無効メイン(文字列[] args){
HashSetの<RectObject>設定=新しいHashSetの<RectObject>();
RectObject R1 =新しいRectObject(3,3)。
RectObject R2 =新しいRectObject(5,5)。
RectObject R3 =新しいRectObject(3,3)。
set.add(R1)。
set.add(R2)。
set.add(R3)。
r3.y = 7。
System.out.println( "删除前的大小サイズ:" + set.size(http://www.my516.com))。
set.remove(R3)。
System.out.println( "删除后的大小サイズ:" + set.size());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
:業績
削除前サイズサイズ:3
サイズの大きさは、削除後:3
ええ、私たちはR3を削除された削除R3オブジェクトを削除し、実際に呼んでこする、問題を発見し、それは大きな問題です除去されていない、これは、メモリリークと呼ばれるオブジェクトではありませんが、彼は記憶に残っていますさ。当社が営業何度した後、メモリがバースト。ソースコードを見て削除:
/ **
。* ITが存在する場合は、このセットから要素で指定された削除し
、正式*より、要素は、ことの<tt> E </ tt>を削除します
O == nullのE(* <tt>に?ヌル==:o.equals(E))</ TT>、
*設定されている場合、このSUCH AN要素は</ TT> trueの場合には、<TT>を返し含まれています。
*要素が同等にこのSET(またはが含まれ、このIF SETは
*変更コールASの結果)。(これはSET含まれません
*一度要素通話に戻ります。)
*
* @param O取り出し、このオブジェクトを設定することがから、IFプレゼント
* @return <TT>真</ TT>セットが含まれている場合、指定された要素
* /
パブリックブール削除(オブジェクトo){
戻りmap.remove(O)== PRESENT。
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
然后再看一下除去方法的源码:
/ **
*存在する場合、このマップから指定されたキーのマッピングを削除します。
*
そのマッピングマップから削除されるべき* @paramキーキー
* <TT>キー</ TT>に関連付けられた以前の値@return、又は
* <TT> NULL </ TT> <TTのマッピングは存在しなかった場合>キー</ TT>。
*(A <tt>にヌル</ TT>
*以前に関連付けられている<TT> NULL </ TT>と<TT>キー</ TT>)。
* /
パブリックV削除(オブジェクトキー){
)入力<K、V> E = removeEntryForKey(キー。
リターン(E == nullのヌル:?e.value)。
}
1
2
3
4
5
6
7
8
9
10
11
12
13
在看一下removeEntryForKey方法源码:
/ **
*指定されたキーに関連付けられたエントリを削除し、返し
のHashMapで*を。HashMapのは、何のマッピングが含まれていない場合はnullを返します
。このキーの*を。
* /
最後のエントリ<K、V> removeEntryForKey(オブジェクトキー){
int型のハッシュ=(キー==ヌル)?0:ハッシュ(キー)。
int型I = indexFor(ハッシュ、table.length)。
エントリ<K、V> PREV =表[i]は、
エントリ<K、V> E = PREV。

一方、(!E = NULL){
エントリ<K、V>次= e.next。
オブジェクトK;
IF(e.hash ==ハッシュ&&
!((K = e.key)==キー||(キー= NULL && key.equals(K)))){
modCount ++。
サイズ - ;
IF(PREV == e)の
テーブル[I] =次。
他に
次= prev.next。
e.recordRemoval(この);
電子を返します。
}
PREV = E。
E =次回。
}

Eリターン;
}
。1
2
3
4
5
6
7
8
9
10
11
12は、
13である
14
15
16
17
18である
19。
20
21である
22である
23である
24
25
26である
27
28
29
30
31で
removeメソッドを呼び出す時に、最初のオブジェクトが使用され、これまで見てきましたハッシュコード値は、オブジェクトを見つけ、それを削除し、我々はyプロパティr3のオブジェクトの値を変更したため、この問題がある、とするのhashCode R3オブジェクトので、yの値を計算に関与しているRectObjectオブジェクトのhashCodeメソッドは、で開催されましたので、変更は、そうR3を見つけることができませんメソッドを削除するので、削除できませんでした。それはR3のhashCodeが変更だが、彼はまだ元の位置に、格納された位置を更新していなかったので、我々は彼の新しいのhashCodeに行ったときに見つけなければなりません。
---------------------

おすすめ

転載: www.cnblogs.com/ly570/p/11331593.html