HashMapのインタビューは、あなたが本当に冷静に現実を直視することができますということであるためにHashMapのは、ほとんどのインタビューは、知識を要求されますか?あなたはインタビューのよく知られたインターネットの会社に行けば、私は絶対にちょうどそのような単純な質問のあなたのHashMapのデータ構造を聞かない、と信じています。私は頻繁に尋ねたインタビューHashMapの中に、最近ボスに関するいくつかの質問を収集しました:
1.なぜ、HashMapのは、2のべき乗でありますか?
new HashMap(14);
HashMapのは、それが実行された後、作成された配列のサイズはどのくらいである上記のコード行、次いで、+リストアレイ(1.8ならびに赤黒木)実装されているのですか?
ソースを追跡することは、配列のサイズを返すために、このような機能を実行することを確認できます。
static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
グラフィック:
- 第一又は右シフト演算と1のうちより後ろ左から右への最初のビットを保証することができ
- 第二または右シフト操作は、左から右へ1 2以上を保証することができます
- そしてように、Javaのint値は4バイトであるため、32ビット、16ビットシフト前回ので、これは2 ^ 32を発生保証するのに十分。
-
この計算機能により、我々は、2 14のn乗の最小値よりも大きい、16 14の動作を得ることができる渡します。
上記の配列の最終的なサイズは、2のn乗、あなたは2のn乗を確保したい理由について、次の話であることを保証します
static int indexFor(int h, int length) {
return h & (length-1);
}
データ長であるようなコードフラグメントを実行するためのPUT要素がハッシュコード値のモジュロ演算を意図jdk1.7時間、です。それが引き継がれたので、なぜそれ番%使用していませんか?%以上のコンピューティングビットコンピューティングの多くの効率的なので。
それは、&演算子であり、そしてなぜその長さが2 ^ nはそれであることを確認しなければならないので?
- 2 ^ N-1の長さは、ハッシュ・テーブルのサイズ範囲の&保証をもたらすことができます。
- モジュロ付き%と計算結果が一致であってもよいです。
2.なぜ、HashMapの拡大係数は0.75でありますか?
負荷率が1場合、負荷率が、大きすぎると、その後スペース利用から、実際にアップし、非常に重要な部分ですが、時間効率が低下しています。
負荷率が小さすぎると、操作のハッシュマップ頻繁に拡張ダウンで、その結果、各拡張は、巨大なパフォーマンスをしている。
大丈夫!言いたいような、この問題について私は開始することができ、言いませんでした。
実際には、これは次のようになります。
Because TreeNodes are about twice the size of regular nodes, we
* use them only when bins contain enough nodes to warrant use
* (see TREEIFY_THRESHOLD). And when they become too small (due to
* removal or resizing) they are converted back to plain bins. In
* usages with well-distributed user hashCodes, tree bins are
* rarely used. Ideally, under random hashCodes, the frequency of
* nodes in bins follows a Poisson distribution
* (http://en.wikipedia.org/wiki/Poisson_distribution) with a
* parameter of about 0.5 on average for the default resizing
* threshold of 0.75, although with a large variance because of
* resizing granularity. Ignoring variance, the expected
* occurrences of list size k are (exp(-0.5) * pow(0.5, k) /
* factorial(k)). The first values are:
*
* 0: 0.60653066
* 1: 0.30326533
* 2: 0.07581633
* 3: 0.01263606
* 4: 0.00157952
* 5: 0.00015795
* 6: 0.00001316
* 7: 0.00000094
* 8: 0.00000006
* more: less than 1 in ten million
0.75は、空間と時間との間の妥協ですが、また、他のプログラミング言語も0.72に設定されている0.75非本質的なことを言っていない]を選択します。
3. jdk1.7拡大が死のどのサイクルのですか?
void transfer(Entry[] newTable, boolean rehash) {
int newCapacity = newTable.length;
for (Entry<K,V> e : table) {
while(null != e) {
Entry<K,V> next = e.next;
if (rehash) {
e.hash = null == e.key ? 0 : hash(e.key);
}
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
}
}
}
私が表現する方法をマップしようとするので、このトピックといえば、それから見て、インターネット上のブログを見つけることは、本当に読み取ることができません
それは無限ループ4 jdk1.8の拡大をもたらすのだろうか?
Node<K,V> loHead = null, loTail = null;
Node<K,V> hiHead = null, hiTail = null;
Node<K,V> next;
do {
next = e.next;
if ((e.hash & oldCap) == 0) {
if (loTail == null)
loHead = e;
else
loTail.next = e;
loTail = e;
}
else {
if (hiTail == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
}
} while ((e = next) != null);
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}
グラフィック分析の下に見て:
だから、jdk1.8のHashMapに拡大はデッドロックを生成しないとき!
5.なぜ赤黒木8への鎖長に到達しますか?
それは赤黒木、8なぜそれがになったときに第一、フットプリントの大きさは、容器8に達した場合にのみ、第二号にポアソン分布によると、説明した二回のTreeNodeノードリストノードでありますリストのノードを参照すると、8の長さは、8の特別な場合が存在すべきである場合に達成するために、リストのみ赤黒木を向けるだろうことは困難である。
赤黒木投入要件要素ハッシュマップは、それが存在する場合64の数。
6. jdk1.8のHashMapのは、スレッドセーフですか?
JDK1.8HashMapも、それが無限ループの問題の拡大を避けるために多くを行うことができますが、しかし、HashMapのスレッドには、例えば、まだ安全ではありません:スレッド置く要素、拡張のためのスレッドB、
マルチスレッド操作で安全ではない理由は、意志一貫性のない状態変数を生じる同一のバリエーションの例。