LinkedHashMapの原則

LinkedHashMap概要

HashMapのは、HashMapのハッシュは、その後、ハッシュコードに入れて対応するキーに基づいて所定の場所に置かれ、無秩序です。だから、HashMapのに入れて、特定の順序で、そして今のHashMapの順序を置く別のトラバース(番号に従ってソートキーが置かれているハッシュコードを除いて、この確率は非常に小さいです)

JAVAは、私たちは秩序HashMapを達成するためにJDK1.4後のLinkedHashMapを提供しています!

LinkedHashMapは、ハッシュマップのサブクラスであり、それは次に、挿入のため、同一の要求出力入力系列なら、選択のLinkedHashMapを保持します。

LinkedHashMapハッシュテーブルと予測可能な繰り返し順序を持つMapインタフェースのリンクリストの実装です。この実装は、オプションのマップ操作の全てを提供し、使用ヌルヌル値及びキーを可能にします。このクラスは、マッピングの順序を保証するものではありません。特に、それは順序が永遠に続くことを保証するものではありません。

LinkedHashMap実現はその中のHashMapとは異なり、のLinkedHashMapは、すべてのエントリの二重リンクリスト内の実行を維持します。このリンクリストは、繰り返し順序を定義し、順序が反復オーダーまたはアクセス順序であってもよいです。

この実装は同期化されていないことに注意してください。複数のスレッドがハッシュマップのリンクにアクセスし、それらのスレッドの少なくとも1つが構造的にマップを変更する場合には、外部同期させる必要があります。

リストの(getメソッド呼び出し)アクセスのために、リストのオーダー、および:リスト内の要素の順序は、に分けることができます。デフォルトはあなたがアクセスのソート順を指定した場合、挿入順でソートされているので、getメソッドを呼び出した後、訪問の要素はリストの末尾に移動します、我々はリストにアクセスするために、ソートされたフォームにアクセスし続けることができます。

小 Demo

私は、アクセスシーケンス、挿入順序を参照してください、のLinkedHashMapを学ぶのは非常に初めにあった、というように、少しめまい、原理はゆっくりと理解しているフォローアップ調査と一緒に、私はあなたのLinkedHashMapを表示するには、最初の数デモ中に行います使用しています。その効果を理解し、その原則を勉強しています。

HashMapの

以下のコードを参照してください。

public static void main(String[] args) {
    Map<String, String> map = new HashMap<String, String>();
    map.put("apple", "苹果");
    map.put("watermelon", "西瓜");
    map.put("banana", "香蕉");
    map.put("peach", "桃子");

    Iterator iter = map.entrySet().iterator();
    while (iter.hasNext()) {
        Map.Entry entry = (Map.Entry) iter.next();
        System.out.println(entry.getKey() + "=" + entry.getValue());
    }
}

コンソール出力を通して比較的簡単なテストHashMapのコードは、私たちは、HashMapのが発注されていないことがわかります。

banana=香蕉
apple=苹果
peach=桃子
watermelon=西瓜

LinkedHashMap

私たちは今、変わらない、のLinkedHashMapに他のコードを実装をマップします。Map<String, String> map = new LinkedHashMap<String, String>();

出力コンソールを見てください:

apple=苹果
watermelon=西瓜
banana=香蕉
peach=桃子

私たちは、出力シーケンスを挿入順序に従って完了したことを見ることができます!私たちは、その上に挿入の順序を保持することである述べました。言及した我々は、上記の中でも、アクセス順序それに応じて並べ替えることができていないですか?はい、私たちは確認するために例を使用します。

public static void main(String[] args) {
    Map<String, String> map = new LinkedHashMap<String, String>(16,0.75f,true);
    map.put("apple", "苹果");
    map.put("watermelon", "西瓜");
    map.put("banana", "香蕉");
    map.put("peach", "桃子");

    map.get("banana");
    map.get("apple");

    Iterator iter = map.entrySet().iterator();
    while (iter.hasNext()) {
        Map.Entry entry = (Map.Entry) iter.next();
        System.out.println(entry.getKey() + "=" + entry.getValue());
    }
}

似ていますが、我々は、コードの2行以上を持ち、初期化時のLinkedHashMapコードの前に、同じではないとのコンストラクタは、コンソール出力を見てみましょう。

watermelon=西瓜
peach=桃子
banana=香蕉
apple=苹果

これは、のLinkedHashMapは、アクセスの順序に従って並べ替えるために選択することができ、我々は前に述べたものです。

LinkedHashMap実装

LinkedHashMapについては、その継承とHashMapの(ためpublic class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>)、すべての要素を保持するために、二重リンクリストで基礎となるハッシュテーブル。基本的な操作は、機能の彼らのリンクリストを達成するために、親に関連するメソッドをオーバーライドすることにより、親クラスHashMapのそれに似ています。のは、のLinkedHashMapソースコードを分析してみましょう:

メンバ変数

ハッシュアルゴリズムのLinkedHashMap用いるとHashMapの同じ、それは配列要素エントリ、現在のオブジェクトの参照を保存するエントリ追加に格納されているだけでなく、要素の前と後の次の要素に保存され、カザフスタンのように再定義リストに基づき、ギリシャの表は、双方向リンクを構成しています。ソースコードを参照してください。

/**
* The iteration ordering method for this linked hash map: <tt>true</tt>
* for access-order, <tt>false</tt> for insertion-order.
* 如果为true,则按照访问顺序;如果为false,则按照插入顺序。
*/
private final boolean accessOrder;
/**
* 双向链表的表头元素。
 */
private transient Entry<K,V> header;

/**
* LinkedHashMap的Entry元素。
* 继承HashMap的Entry元素,又保存了其上一个元素before和下一个元素after的引用。
 */
private static class Entry<K,V> extends HashMap.Entry<K,V> {
    Entry<K,V> before, after;
    ……
}

HashMapのエントリエントリに統合でのLinkedHashMap、それは前と参照した後に増加するが、基準要素と次の要素を指します。

初期化

コンストラクタのLinkedHashMapにおけるソースコードから分かるように、実際の呼関連のHashMapの親クラスのコンストラクタは、ストレージアレイの基礎となるテーブルを構築するが、さらに設定されていない場合、このパラメータaccessOrderを増加させることができる、デフォルトのため、偽であります挿入順序の反復のために、コースが明示的にtrueに設定され、代表的な反復が順番にアクセスします。以下のような:

public LinkedHashMap(int initialCapacity, float loadFactor,boolean accessOrder) {
    super(initialCapacity, loadFactor);
    this.accessOrder = accessOrder;
}

我々はすでにentry要素ののLinkedHashMapは、機能の二重リンクリストを提供する、エントリのHashMapを継承知っています。コンストラクタのHashMapで、そして最後のinit()メソッドは、関連した初期化を呼び出し、このメソッドは、関連するサブクラスの初期化コールを実装するためにのみ利用可能な、ハッシュマップの実装では意味がありません。

しかし、書き換えのLinkedHashMap init()メソッドは、親クラスのコンストラクタ完成した構造を呼び出した後、その要素エントリの更なる初期化動作を達成します。

/**
* Called by superclass constructors and pseudoconstructors (clone,
* readObject) before any entries are inserted into the map.  Initializes
* the chain.
*/
@Override
void init() {
  header = new Entry<>(-1, null, null, null);
  header.before = header.after = header;
}

メモリ

LinkedHashMap親クラスHashMapのPUTメソッドをオーバーライドするが、メソッドオーバーライドサブ置く方法は、親クラスHashMapの空隙recordAccess(HashMapのm)を呼び出しボイドaddEntry(int型のハッシュ、Kキー、V値、bucketIndexをINT)としません無効createEntry(int型のハッシュ、Kキー、V値、bucketIndexをint型)は、実装は独自の双方向リンクリストを所有しています。HashMapの以前の記事で、私たちが置かれている方法は、私たちがここにいるのHashMapのputメソッドのソースコードを再掲載し、説明しました:

HashMap.put:

public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key);
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);
        return null;
}

メソッドをオーバーライドします。

void recordAccess(HashMap<K,V> m) {
    LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
    if (lm.accessOrder) {
        lm.modCount++;
        remove();
        addBefore(lm.header);
        }
}

void addEntry(int hash, K key, V value, int bucketIndex) {
    // 调用create方法,将新元素以双向链表的的形式加入到映射中。
    createEntry(hash, key, value, bucketIndex);

    // 删除最近最少使用元素的策略定义
    Entry<K,V> eldest = header.after;
    if (removeEldestEntry(eldest)) {
        removeEntryForKey(eldest.key);
    } else {
        if (size >= threshold)
            resize(2 * table.length);
    }
}

void createEntry(int hash, K key, V value, int bucketIndex) {
    HashMap.Entry<K,V> old = table[bucketIndex];
    Entry<K,V> e = new Entry<K,V>(hash, key, value, old);
    table[bucketIndex] = e;
    // 调用元素的addBrefore方法,将元素加入到哈希、双向链接列表。  
    e.addBefore(header);
    size++;
}

private void addBefore(Entry<K,V> existingEntry) {
    after  = existingEntry;
    before = existingEntry.before;
    before.after = this;
    after.before = this;
}

読みます

LinkedHashMap書き換えGET HashMapの親クラス、親クラスのgetEntry(への実際の呼び出し)の要素を取得する方法を見つけ、その後、ソートモードaccessOrderがアクセスシーケンスを記録し、真である場合を決定、二重にリンクされたリストにアクセスするために新しい要素を追加しますヘッダと、元の場所からそれを取り除きます。リストの増加、一定のレベルを削除するには、それがパフォーマンスの低下をもたらすものではありません。

public V get(Object key) {
    // 调用父类HashMap的getEntry()方法,取得要查找的元素。
    Entry<K,V> e = (Entry<K,V>)getEntry(key);
    if (e == null)
        return null;
    // 记录访问顺序。
    e.recordAccess(this);
    return e.value;
}

void recordAccess(HashMap<K,V> m) {
    LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
    // 如果定义了LinkedHashMap的迭代顺序为访问顺序,
    // 则删除以前位置上的元素,并将最新访问的元素添加到链表表头。  
    if (lm.accessOrder) {
        lm.modCount++;
        remove();
        addBefore(lm.header);
    }
}

/**
* Removes this entry from the linked list.
*/
private void remove() {
    before.after = after;
    after.before = before;
}

/**clear链表,设置header为初始状态*/
public void clear() {
 super.clear();
 header.before = header.after = header;
}

ソートモード

偽の挿入配列、;のLinkedHashMap accessOrderは真のために、アクセス順序のために、ブール変数属性でソートモードを、定義されました。通常の状況で、あなたは挿入配列のデフォルトの繰り返し順序でソートモードを指定する必要はありません。

これらは、挿入順序を指定されたデフォルトコンストラクタソートモードです。あなたがのLinkedHashMapを構築したい、と最近要素を保存することがほとんどを訪問し、その後のLinkedHashMap以下のコンストラクタを使用するために(つまり、アクセス順序)の最近の最小値からのアクセスを押ししようとする場合:公共のLinkedHashMap(int型InitialCapacityの値、loadFactor、ブールaccessOrderフロート)

繰り返し順序は、ハッシュマップの順序は、このマッピングは、LRUキャッシュを構築するために適している場合、そのエントリの最後の訪問です。LinkedHashMap removeEldestEntry(のMap.Entry <K、V>長男)方法を提供します。このメソッドは、このマップは、最も古い要素を削除することはできません法線マッピングの動作に似ています、あなたが偽のデフォルトの戻りで、最も古いエントリの新しいエントリー・プロシージャを追加するたびに削除するので、提供することができます。

私たちは、今後の記事でのLinkedHashMap詳細を構築する方法についてのLRUキャッシュを紹介します。

概要

実際には、ほとんどのLinkedHashMapのHashMapのように:技術的には、エントリ<K、V>ヘッダを定義することを除いて、このヘッダーは、表にない、それは追加の独立アウトです。LinkedHashMapハッシュマップエントリ<K、V>の継承によって、そして後に、前に二つの属性エントリ<K、V>を追加し、アクセス順序またはシーケンスを達成するために、挿入ソートをヘッダ二重連結リストを形成するために一緒に組み合わせることができます。

実装に遭遇した問題は、私の地図の尋ね反復挿入順序に従って行うことができる前に、面接のプロセスを覚えて、中のLinkedHashMapについて書くの過程で?その時に脳が突然短絡されているが、今私が思うことを、これだけの知識を習得するのに十分な、まだ固体自分を責めることができ、それはまた、最初からコードであり、慎重に再びそれを読みます。

しかし、私の提案は、私たちが最初にすべてのすべてのことの最初のを覚えておく必要があるということです:のLinkedHashMap反復挿入順序やアクセス順序を行うことができ、私たちの将来の開発でこの出会い同様の問題、のLinkedHashMapを使用して考えるために取り組むべき、でも、その内部構造は非常に理解され、使用しない全く使用することはありません。

私たちの研究の目的は、より良いアプリケーションにあります。

おすすめ

転載: www.cnblogs.com/baojun/p/11086996.html