設定インタフェースは、Java Collections Frameworkであることを特徴としている1、次のとおりです。重複要素を含めることはできませんし、最大1つの許可ヌル要素を。一般的にJavaのセット実装クラスで使用される3つがあります。
- HashSetの:要素が中に保存されているハッシュテーブル、最高のパフォーマンスが、繰り返しの要素の順序を保証することはできません
- LinkedHashSetの:で、全体のすべての要素のリストを維持する挿入順序要素の反復
- TreeSetの:に格納された要素赤黒木、素子サイズでソート反復配列
この3の実現にJDK を設定し HashMapの、のLinkedHashMapとTreeMapを、他の出版された論文の3つの地図のソースコード解析は、このサイトを見ることができる上:コア機能のセットは、実際に委任されています。
設定された次の簡単な分析のこれら三組のソース、および問題解決には、インタビューの一部を発生することがあります。
HashSetの
注釈が削除された場合、また、配列およびクローニング方法に加えて、HashSetのソース線200、について次のように
public class HashSet<E> extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable {
// 实际存储元素的对象
private transient HashMap<E,Object> map;
// 存储在 HashMap 中所有 key 的共享的 value 值
private static final Object PRESENT = new Object();
// 空构造函数
public HashSet() {
map = new HashMap<>(); // 0.75f 加载因子
}
// 使用已有集合填充并初始化
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
// 指定关联 HashMap 的初始容量和加载因子
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
// 只指定初始容量
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
// 包访问权限的构造方法,仅用于 LinkedHashSet 初始化
// 使用 LinkedHashMap 作为底层存储
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
// HashSet 中的元素就相当于 HashMap 中的 key
public Iterator<E> iterator() {
return map.keySet().iterator();
}
// 以下这些方法,都是对 Set 接口中定义的方法的实现
public int size() {
return map.size();
}
public boolean isEmpty() {
return map.isEmpty();
}
public boolean contains(Object o) {
return map.containsKey(o);
}
// 所有键值对的 value 值都是 PRESENT 这个 Object 对象
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
public void clear() {
map.clear();
}
// JDK 8 提供的一种并行遍历机制 - 可分割迭代器
public Spliterator<E> spliterator() {
return new HashMap.KeySpliterator<E,Object>(map, 0, -1, 0, 0);
}
}
、根底にあるの利用見ることができたHashMapながら、実際のデータストレージ用のPRESENTは値のすべてのマップの値に書き込まれます。コア機能が委譲され、比較的単純であるのHashMap。
かどうか設定されているマップは、すべてのストレージオブジェクト Javaで、2つのオブジェクトが等しいかどうかを判断するには、を介してすべてのequalsとhashCodeを二つの方法:
- 2つのオブジェクトが等しい等号を決定することにより、それらは同じハッシュコードを返す必要があります
- 一方、同じハッシュコードを持つ必要はありません
したがって、オブジェクト格納HashSetのは、適切なカバレッジを達成しなければならないと等しいとハッシュコードの2つの方法。
実際には、のHashSetの要素は、実際にはHashMapでキーを挿入するとき、:
- ハッシュコードは、第1の下地アレイの記憶場所を見つけるために、要素の値を計算します
- そして、この位置でのすべての要素は、equalsメソッドを使用して比較しました
- 等しくない場合には、挿入し、それ以外の場合は、更新値を行うためにここに本質的には、挿入されていないが、キーは変更されません。
約イテレータは KeyIteratorでHashMapの使用です。
LinkedHashSetの
LinkedHashSetのコードより簡単な、それは次のようにコードは、HashSetのから継承します。
public class LinkedHashSet<E> extends HashSet<E>
implements Set<E>, Cloneable, java.io.Serializable {
// 调用父类特定的构造方法,初始一个 LinkedHashMap
public LinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
}
public LinkedHashSet(int initialCapacity) {
super(initialCapacity, .75f, true);
}
public LinkedHashSet() {
super(16, .75f, true);
}
public LinkedHashSet(Collection<? extends E> c) {
super(Math.max(2*c.size(), 11), .75f, true);
addAll(c);
}
@Override
public Spliterator<E> spliterator() {
return Spliterators.spliterator(this, Spliterator.DISTINCT | Spliterator.ORDERED);
}
}
これらのすべてのコードは、それがのコンストラクタことは注目に値するスーパーコールはHashSetのにデフォルトコンストラクタ・パケット・アクセスで、コア機能は、のLinkedHashMapに委任されています。
そのようなHashSetのは、あなたは追加の基本的な操作のセットを完了し、一定の時間内に含まれてい削除することができます。パフォーマンスの追加を維持するので、HashSetのよりも若干低いリストを。トラバース時に一つの例外を除いて、LinkedHashSetの時間を過ごし、要素の数は、それがされているため、HashSetのに比例しているが、より多くの時間を要する容量設定比例。
TreeSetの
TreeSetのがされた注文の設定を設定するには、要素のサイズを使用すると、コンパレータのコンパレータを指定することができ、天然の配列の比較モードかもしれません。
それはのTreeMapの要素に指定された要素よりも大きいパッケージ、トラバース例えば、それぞれ、下部床、天井などの順序付けられたセットで提供されるAPI、およびより高いリターン以上、未満、以下、。することができログ(n)を設定する基本的な操作が含まれ、追加および削除時間以内に完了する。
理解するために次のことは、設定インタフェース定義は、使用することです等号の方法は、平等のための要素を比較し、TreeSetの利用があるのcompareToまたは比較満たして比較した方法、一連の行動を、しかし、Setインタフェースの仕様に準拠していませんでした。
TreeSetのソースコードは、結局、TreeMapのパッケージのほんの少しは、ここでは比較的単純で掲載されていません。
インタビューの質問の要約の共通セット
一般的にコレクションの一部を使用したソースコードを分析する前に、これらのコレクションそれぞれ独自の特徴を持って、その違いは、多くの場合、インタビューの中で、我々は以下に要約されている一般的な面接の質問に終わる表示されます。
ArrayListのとLinkedListの違いは何ですか?
- 根底にある使用して、異なるストレージ構造、ArrayListの配列を、LinkedListの使用して二重にリンクされたリストを
- 性能は、ArrayListにはすることができ、ランダムアクセスが、遅い追加および削除効率は、メモリコピーを含む、唯一のLinkedListまたはわずかに大きいため、メモリを注文アクセスを逆転するが、高効率インデル
- またとしてLinkedListのスタックとキューの使用
- ヌルおよび可能両方のストレージ要素は、繰り返しの記憶を可能にします
- どちらも、あなたがCollections.synchronizedList(リストを使用することができ、スレッドセーフで
リスト)メソッドは、スレッドセーフリストを作成します
ArrayListのとベクトルの違いは何ですか?
- 非スレッドセーフなArrayListに、ベクトルのスレッドの安全性
- 場合拡大、容量のArrayListの1.5倍の増加、容量のベクトル2倍の増加
JDK 8 DUI HashMapのは、最適化するために、何をやっていましたか?
- 以下の下にある構造単鎖+アレイ+赤黒木 O(N)のクエリ時間計算からハッシュ衝突の多数が、Oに還元されるストレージ構造、(ログ(N))
- ハッシュ関数の最適化、1.7ビット演算で4 + 5 XOR動作は、1ビットのXOR演算1 +に還元されます
- 最適化された膨張機構は、1.7が再ハッシュされる新しい場所を、1.8に基づいている間、拡張2の電源機構、位置を再計算しない、のみ、元のハッシュ値に基づいて算出される同一の位置または部分のいずれかをオフセット古い配列のオフセット容量をシフト
HashMapのとハッシュテーブルの違い
- HashMapのスレッドセーフ;ハッシュテーブルスレッドセーフ
- HashMapのキーことができますし、ヴァーレはnullです。ハッシュテーブルのキーを許可され、値はnullです
- 2 ^ 4 2 ^ n個のハッシュマップのデフォルトのサイズ及び容量である必要があり、ハッシュテーブル、デフォルトの容量は11(素数)であり、必ずしも2 ^ Nではありません
- 直接用いてハッシュテーブル剰余演算を HashMapの使用、ハッシュバケットのインデックスを計算するために&ビット単位の最適化
HashMapのとのLinkedHashMapの違い
- LinkedHashMapは、彼らが同じストレージ構造と展開のメカニズムを持っているのHashMapから継承されました
- 追加の内部のLinkedHashMapの必要性リストを維持
- LinkedHashMap オーダー要素の反復とHashMapの繰り返し順序予測不可能
- LinkedHashMapができるアクセス順構築するための要素を横断LRUキャッシュを
高速失敗は何で、原理は何ですか?
高速失敗、それはあなたがコレクションの構造を発見した場合、コレクションの横断中、高速で失敗するのは、例外がConcurrentModificationExceptionが実行をスローされます、変更されています。
なお、同期の変更の場合には、それはそれだけで同時変更のエラーを検出するための努力ですが、それが起こるのだろう保証することはできません。
原理は値が予期しない変更を起これば、それは意志、イテレータを返し、それはmodCount現在の値をキャッシュする反復子を呼び出すとき(リスト構造を変更する回数を記録modCountフィールド、)によって達成されます次に投げ、操作を削除します。
概要
この論文の導入だけでなく、すべての従来、一般的に使用される、非スレッドセーフなコレクションの実装のコレクションの前に、次は、Javaのコレクションとスレッドセーフな契約の下で、およびいくつかの特別な目的のコレクションの実装を紹介します。