Javaソースコード解析Hashtableのコレクションシリーズ(XI)入門
序文
私たちは、ソースコードは、競合が使用し、比較のためになる方法を参照するために、我々は詳細にソースコードを解析し、このセクションでは、法律やオープンチェーンアドレス法を、対応する2つの方法を使用し、ハッシュアルゴリズムや紛争解決に実現しました我々は、変更することができますどのような場所、達成しています。
Hashtableのソースコード解析
次のように私たちは、Hashtableのインスタンス化キーを追加することによって操作コンソールの新機能の背後にあるサンプルコードを分析します:
パブリック静的無効メイン(文字列[] args){ ハッシュテーブルハッシュテーブル=新しいHashtableの()。 hashtable.put(-100、 "第一")。 }
私たちはハッシュテーブルを初期化するとき、次は何の仕事をする準備の後ろに、見て?
パブリックハッシュテーブルクラスが<Kは、V> 辞書<Kを、V>延び 実装地図<K、V>、Cloneableを、java.io.Serializableの{ //キー値データを格納する プライベート過渡エントリ<??> []テーブル。 //保存データサイズ プライベート過渡のint型のCOUNT; //しきい値:.(INT)(*容量loadFactor)) プライベートint型のしきい値; //ロードファクター:時間と空間コストのトレードオフは、0.75をデフォルト。より高い値が頭上スペースは減少しますが、時間コストの増加が要素を見つけることがあるので プライベートloadFactorフロート; //指定された容量と負荷率のコンストラクタを {公共のHashtable(int型のInitialCapacityの値、フロートloadFactor)を IF(InitialCapacityの値は<0) はIllegalArgumentException新しい新を投げます( "違法容量:" + InitialCapacityの値)。 IF(loadFactor <= 0 || Float.isNaN(loadFactor)) IF(loadFactor <= 0 || Float.isNaN(loadFactor)) 新しい新しいはIllegalArgumentException投( "無効な負荷:" + loadFactor); IF(InitialCapacityの値== 0) 。InitialCapacityの値= 1; ; this.loadFactor loadFactor = <??、> =新しい新しいエントリテーブル[InitialCapacityの値]; //デフォルト閾値8 閾値=(INT)Math.min(InitialCapacityの値* loadFactor、MAX_ARRAY_SIZE + 1); } //コンストラクタ指定された容量 公共ハッシュテーブル(INT InitialCapacityの値){ この(InitialCapacityの値、0.75F); } //引数なしのデフォルトコンストラクタ(初期容量図11は、負荷率)0.75Fである ハッシュテーブル(){公共 この(11、0.75F); } プライベート静的クラスエントリ<K、V>のMap.Entryの実装<Kは、V> { 最終ハッシュをint型。 最終Kキー。 V値。 エントリ<K、V>次。 保護されたエントリ(int型のハッシュ、Kキー、Vの値が、次のエントリ<K、V>){ this.hash =ハッシュ。 this.key =キー。 this.value =値。 this.next =次回。 } } }
ハッシュテーブルの容量と負荷係数を初期化するときエントリ鎖構造は、ハッシュ衝突アドレス方式を解決するために見ることができる使用して指定されていない場合、データを格納することにより、内部エントリハッシュテーブルアレイは、11のデフォルトの初期容量は、負荷率は、閾値が8で、0.75であります容量が0〜1と容量または指定された容量で算出0特に指定の閾値の閾値容量値が* 0.75 *指定された負荷率計算が優勢に等しい場合の例外は、0未満の容量スローされます。
我々はすぐに結論上記の定義に来ることができるようになり、この時点では、我々はあまりにも多くのさらなる議論を持っていない私たちは、キーと値のペアとして上記のデータを追加するとき、我々は見て、内部はソースコードや変数としてそれを行う方法を介して行われ?
公共同期Vプット(Kキー、V値){ 場合(値== nullが){ )(新しいNullPointerExceptionがスロー。 } 入力タブ[] =表<、?>。 INTハッシュ= key.hashCode()。 INT指数=(ハッシュ&0x7FFFFFFFで)%のtab.length。 エントリ<K、V> =エントリ(エントリ<K、V>)タブ[インデックス]。 (;エントリ= NULL;!エントリー= entry.next){のため であれば((entry.hash ==ハッシュ)&& entry.key.equals(キー)){ V =古いentry.value。 entry.value =値。 古い返します。 } } addEntry(ハッシュ、キー、値、指数)。 ヌルを返します。 }
私たちは一歩一歩を分析し、例外がスローされた場合は、最初のハッシュ値はキーを取得するために追加された後、空の値を追加し、ここでの焦点は、どのような役割次のコードはありますか?
INT指数=(ハッシュ&0x7FFFFFFFで)%のtab.length。
配列インデックスは、キー変換正のハッシュ値によってので、ここでは、論理演算負することができないので、それは、本質的に指数が正の場合、であることを確認するためには、 int型のインデックス=(ハッシュ&0x7FFFFFFFで) %タブ。 長さ、それを計算するためにどのように?、バイナリは、11111111111111111111111110011100バイナリ論理和演算に変換し、それが正のシンボル0すなわち01111111111111111111111111111111あるので0x7FFFFFFFでバイナリ1111111111111111111111111111111は、であり、そして我々は-100の値に追加し、最終的な結果は01111111111111111111111110011100ある小数します我々の計算の原理を説明することである2147483548結果は、我々が実際に0x7FFFFFFFでは2147483647である進小数を減算することにより、我々は最終的に得られる、(100-1)、すなわち99に基づいて直接引くことができますまた、2147483548。最後に、金型11の初期容量の結果を取ることインデックス1です。キーは、ハッシュ値が、その後問題はない肯定的である場合、つまり、論理AND演算結果のハッシュ値で元の値です。それから私は、配列のインデックスに対応する位置を取得し、その後、ループ、疑問は、なぜ、配列サイクルをしていますか?つまり、以下のコードの断片です。
(;エントリ= NULL;!エントリー= entry.next){のため であれば((entry.hash ==ハッシュ)&& entry.key.equals(キー)){ V =古いentry.value。 entry.value =値。 古い返します。 } }
上記を解決するために、対応するキー値がカバーされ、または理解できないであろうと同じですか?次のように私たちは、コンソールでのコードの行を追加します。
パブリック静的無効メイン(文字列[] args){ ハッシュテーブルハッシュテーブル=新しいHashtableの()。 hashtable.put(-100、 "第一")。 hashtable.put(-100、 "第二")。 }
我々は、循環のソースの我々の分析により、-100であるキーをカバーするために値を追加すると、我々は同じキーを追加し、後者が発生した場合、最初の値を置き換える、この時間は、換言すれば、第1、第2行の上にあります戻り値がカバーされ、状況を説明するためには表示されませんnullの場合、以前の値は、と我々はまた、同じキー、戻り値が覆われているの存在を示す、そうでない場合は、戻り値があり、知っている価値が返すことができます。我々は、同じ結合が直接本スローされたときに、得ることができるデータがプリントアウトし、この点C#ハッシュテーブル異なる動作をハッシュテーブル。
序文
私たちは、ソースコードは、競合が使用し、比較のためになる方法を参照するために、我々は詳細にソースコードを解析し、このセクションでは、法律やオープンチェーンアドレス法を、対応する2つの方法を使用し、ハッシュアルゴリズムや紛争解決に実現しました我々は、変更することができますどのような場所、達成しています。
Hashtableのソースコード解析
次のように私たちは、Hashtableのインスタンス化キーを追加することによって操作コンソールの新機能の背後にあるサンプルコードを分析します:
パブリック静的無効メイン(文字列[] args){ ハッシュテーブルハッシュテーブル=新しいHashtableの()。 hashtable.put(-100、 "第一")。 }
私たちはハッシュテーブルを初期化するとき、次は何の仕事をする準備の後ろに、見て?
パブリックハッシュテーブルクラスが<Kは、V> 辞書<Kを、V>延び 実装地図<K、V>、Cloneableを、java.io.Serializableの{ //キー値データを格納する プライベート過渡エントリ<??> []テーブル。 //保存データサイズ プライベート過渡のint型のCOUNT; //しきい値:.(INT)(*容量loadFactor)) プライベートint型のしきい値; //ロードファクター:時間と空間コストのトレードオフは、0.75をデフォルト。より高い値が頭上スペースは減少しますが、時間コストの増加が要素を見つけることがあるので プライベートloadFactorフロート; //指定された容量と負荷率のコンストラクタを {公共のHashtable(int型のInitialCapacityの値、フロートloadFactor)を IF(InitialCapacityの値は<0) はIllegalArgumentException新しい新を投げます( "違法容量:" + InitialCapacityの値)。 IF(loadFactor <= 0 || Float.isNaN(loadFactor)) スロー新しい新はIllegalArgumentException( "無効な負荷:" + loadFactor); IF(InitialCapacityの値== 0) 。InitialCapacityの値= 1; this.loadFactor = loadFactor; 表新しい新しい=エントリ< ??、> [InitialCapacityの値]; //デフォルト閾値8。 閾値=(INT)Math.min(InitialCapacityの値* loadFactor、MAX_ARRAY_SIZE + 1); } //コンストラクタ指定された容量 公共ハッシュテーブル(INT InitialCapacityの値){ この(InitialCapacityの値、 0.75F); } 引数なし//デフォルトコンストラクタ(11初期容量、負荷係数は0.75Fである) パブリックハッシュテーブル(){ この(11、0.75F); } プライベート静的クラスエントリ<K、V>のMap.Entryの実装<Kは、V> { 最終ハッシュをint型。 最後のKキー。 V値。 エントリ<K、V>次。 保護されたエントリ(int型のハッシュ、Kキー、Vの値が、次のエントリ<K、V>){ this.hash =ハッシュ。 this.key =キー。 this.value =値。 this.next =次回。 } } }
ハッシュテーブルの容量と負荷係数を初期化するときエントリ鎖構造は、ハッシュ衝突アドレス方式を解決するために見ることができる使用して指定されていない場合、データを格納することにより、内部エントリハッシュテーブルアレイは、11のデフォルトの初期容量は、負荷率は、閾値が8で、0.75であります容量が0〜1と容量または指定された容量で算出0特に指定の閾値の閾値容量値が* 0.75 *指定された負荷率計算が優勢に等しい場合の例外は、0未満の容量スローされます。
我々はすぐに結論上記の定義に来ることができるようになり、この時点では、我々はあまりにも多くのさらなる議論を持っていない私たちは、キーと値のペアとして上記のデータを追加するとき、我々は見て、内部はソースコードや変数としてそれを行う方法を介して行われ?
公共同期Vプット(Kキー、V値){ 場合(値== nullが){ )(新しいNullPointerExceptionがスロー。 } 入力タブ[] =表<、?>。 INTハッシュ= key.hashCode()。 INT指数=(ハッシュ&0x7FFFFFFFで)%のtab.length。 エントリ<K、V> =エントリ(エントリ<K、V>)タブ[インデックス]。 (;エントリ= NULL;!エントリー= entry.next){のため であれば((entry.hash ==ハッシュ)&& entry.key.equals(キー)){ V =古いentry.value。 entry.value =値。 古い返します。 } } addEntry(ハッシュ、キー、値、指数)。 ヌルを返します。 }
私たちは一歩一歩を分析し、例外がスローされた場合は、最初のハッシュ値はキーを取得するために追加された後、空の値を追加し、ここでの焦点は、どのような役割次のコードはありますか?
INT指数=(ハッシュ&0x7FFFFFFFで)%のtab.length。
配列インデックスは、キー変換正のハッシュ値によってので、ここでは、論理演算負することができないので、それは、本質的に指数が正の場合、であることを確認するためには、 int型のインデックス=(ハッシュ&0x7FFFFFFFで) %タブ。 長さ、それを計算するためにどのように?、バイナリは、11111111111111111111111110011100バイナリ論理和演算に変換し、それが正のシンボル0すなわち01111111111111111111111111111111あるので0x7FFFFFFFでバイナリ1111111111111111111111111111111は、であり、そして我々は-100の値に追加し、最終的な結果は01111111111111111111111110011100ある小数します我々の計算の原理を説明することである2147483548結果は、我々が実際に0x7FFFFFFFでは2147483647である進小数を減算することにより、我々は最終的に得られる、(100-1)、すなわち99に基づいて直接引くことができますまた、2147483548。最後に、金型11の初期容量の結果を取ることインデックス1です。キーは、ハッシュ値が、その後問題はない肯定的である場合、つまり、論理AND演算結果のハッシュ値で元の値です。それから私は、配列のインデックスに対応する位置を取得し、その後、ループ、疑問は、なぜ、配列サイクルをしていますか?つまり、以下のコードの断片です。
(;エントリ= NULL;!エントリー= entry.next){のため であれば((entry.hash ==ハッシュ)&& entry.key.equals(キー)){ V =古いentry.value。 entry.value =値。 古い返します。 } }
上記を解決するために、対応するキー値がカバーされ、または理解できないであろうと同じですか?次のように私たちは、コンソールでのコードの行を追加します。
パブリック静的無効メイン(文字列[] args){ ハッシュテーブルハッシュテーブル=新しいHashtableの()。 hashtable.put(-100、 "第一")。 hashtable.put(-100、 "第二")。 }
我々は、循環のソースの我々の分析により、-100であるキーをカバーするために値を追加すると、我々は同じキーを追加し、後者が発生した場合、最初の値を置き換える、この時間は、換言すれば、第1、第2行の上にあります戻り値がカバーされ、状況を説明するためには表示されませんnullの場合、以前の値は、と我々はまた、同じキー、戻り値が覆われているの存在を示す、そうでない場合は、戻り値があり、知っている価値が返すことができます。我々は、同じ結合が直接本スローされたときに、得ることができるデータがプリントアウトし、この点C#ハッシュテーブル異なる動作をハッシュテーブル。