Linked HashMapのソースコード(JDK 1.7)の解読
3362 ワード
前の主なHashMapのソースコードの解読。今回はLinked HashMapを研究しています。
Linked HashMapはHashMapを継承し、双方向チェーンを追加してハッシュ衝突を解決します。
一、コンストラクタ
コンストラクタはHashMapと同じで、HashMapのコンストラクタを呼び出して、accessOrder変数を追加しました。いろいろなコンストラクタを呼び出してtrueまたはfalseを設定します。同時にinit()方法を書きました。
二、保存データput()
まず今のチェーンのノードを見てください。
1)keyがnullであれば、keyに対応するhash値を0とし、テーブル配列の0番目の位置に置く。
2)keyがnullでない場合、hash関数から対応するhash値を得て、hash値から対応するテーブル配列のインデックス値を見つけます。
3)対応する位置のチェーン要素に該当するkey値があれば、直接データを更新する
4)新しいkeyとvalueをチェーンに追加しないと、Linked HashMapでaddEntry()とcreateEntry()を複写します。
addEntry()は、最初に要素を加えるかどうかを判定するロジックを追加しました。デフォルトはfalseです
同じHashMapで、直接呼び出したのはshMapのget()です。
四、まとめ
スレッド同期
key/valueはnullを許可しますか?
key/valueは重複を許可していますか?
Linked HashMap
サポートしない
許可
keyは重複を許さない/valueは重複を許さない
HashMapとの違いは、Linked HashMap内部では、ハッシュ・衝突とレコードの挿入順序を解決するための双方向チェーン・テーブルを維持することにある。
Linked HashMapはHashMapを継承し、双方向チェーンを追加してハッシュ衝突を解決します。
一、コンストラクタ
コンストラクタはHashMapと同じで、HashMapのコンストラクタを呼び出して、accessOrder変数を追加しました。いろいろなコンストラクタを呼び出してtrueまたはfalseを設定します。同時にinit()方法を書きました。
@Override
void init() {
header = new Entry<>(-1, null, null, null);
header.before = header.after = header;
}
この方法では、ハッシュ衝突を解決するために双方向チェーンテーブルを初期化する。accessOrderはアクセス順序を制御し、trueであれば、get()要素の時に要素を並べ替え、先ほどgetした元素をリンクの最後のノードに調整し、falseであれば、挿入順に要素を格納する。二、保存データput()
まず今のチェーンのノードを見てください。
private static class Entry extends HashMap.Entry {
// 、
Entry before, after;
Entry(int hash, K key, V value, HashMap.Entry next) {
super(hash, key, value, next);
}
/**
* ,
*
*/
private void remove() {
before.after = after;
after.before = before;
}
/**
*
*/
private void addBefore(Entry existingEntry) {
after = existingEntry;
before = existingEntry.before;
before.after = this;
after.before = this;
}
/**
*
*/
void recordAccess(HashMap m) {
LinkedHashMap lm = (LinkedHashMap)m;
if (lm.accessOrder) {
lm.modCount++;
remove();
addBefore(lm.header);
}
}
void recordRemoval(HashMap m) {
remove();
}
}
データを保存しても呼び出されるのは、親タイプのHashMapのput()です。つまりkeyとvalueに加入する時:1)keyがnullであれば、keyに対応するhash値を0とし、テーブル配列の0番目の位置に置く。
2)keyがnullでない場合、hash関数から対応するhash値を得て、hash値から対応するテーブル配列のインデックス値を見つけます。
3)対応する位置のチェーン要素に該当するkey値があれば、直接データを更新する
4)新しいkeyとvalueをチェーンに追加しないと、Linked HashMapでaddEntry()とcreateEntry()を複写します。
addEntry()は、最初に要素を加えるかどうかを判定するロジックを追加しました。デフォルトはfalseです
void addEntry(int hash, K key, V value, int bucketIndex) {
super.addEntry(hash, key, value, bucketIndex);
//
Entry eldest = header.after;
if (removeEldestEntry(eldest)) {
removeEntryForKey(eldest.key);
}
}
createEntryとは、この双方向チェーンを作成することであり、HashMapでシングルチェーンテーブルを作成する考え方と同じです。 void createEntry(int hash, K key, V value, int bucketIndex) {
HashMap.Entry old = table[bucketIndex];
Entry e = new Entry<>(hash, key, value, old);
table[bucketIndex] = e;
e.addBefore(header);
size++;
}
三、データgetを取る()同じHashMapで、直接呼び出したのはshMapのget()です。
public V get(Object key) {
Entry e = (Entry)getEntry(key);
if (e == null)
return null;
e.recordAccess(this);
return e.value;
}
データを取る時、根拠が見えます。 accessOrderはtrueでアクセス順序を調整するかどうか、trueであれば、現在訪問しているkeyに対応するノードをリンクの最後のノードに調整します。四、まとめ
スレッド同期
key/valueはnullを許可しますか?
key/valueは重複を許可していますか?
Linked HashMap
サポートしない
許可
keyは重複を許さない/valueは重複を許さない
HashMapとの違いは、Linked HashMap内部では、ハッシュ・衝突とレコードの挿入順序を解決するための双方向チェーン・テーブルを維持することにある。