Heim > Java > javaLernprogramm > Hauptteil

Beispiel für das Parsen des LinkedHashMap-Quellcodes in Java

黄舟
Freigeben: 2017-09-29 09:52:24
Original
1240 Leute haben es durchsucht

In diesem Artikel wird hauptsächlich der LinkedHashMap-Quellcode in Java analysiert, der einen bestimmten Referenzwert hat.

Übersicht:

LinkedHashMap-Implementierung Map erbt HashMap , basierend auf der Hashtabellen- und Kettenlistenimplementierung von Map, mit vorhersehbarer Iterationsreihenfolge.

LinedHashMap verwaltet eine doppelt verknüpfte Listenstruktur, die für alle Einträge gilt. Die verknüpfte Liste definiert die Iterationsreihenfolge, die Einfüge- oder Zugriffsreihenfolge sein kann.

Das Knotenobjekt von LintHashMap erbt das Knotenobjekt von HashMap und fügt Vorher- und Nachher-Zeiger hinzu:


/**
 * LinkedHashMap节点对象
 */
 static class Entry<K,V> extends HashMap.Node<K,V> {
  Entry<K,V> before, after;
  Entry(int hash, K key, V value, Node<K,V> next) {
   super(hash, key, value, next);
  }
 }
Nach dem Login kopieren

lintHashMap-Initialisierung:

accessOrder wird, einfach ausgedrückt, verwendet, um die Reihenfolge der Elemente zu steuern.
accessOrder ist wahr: Es bedeutet, dass es in der Reihenfolge des Zugriffs gespeichert wird, das heißt, wer zuerst darauf zugreift, wird zuerst eingestuft accessOrder ist falsch, was bedeutet, dass es in der Reihenfolge des Zugriffs gespeichert wird. Die Reihenfolge ist die Reihenfolge, in der Sie die Elemente platzieren.


public LinkedHashMap(int initialCapacity, float loadFactor) {
  super(initialCapacity, loadFactor);
  accessOrder = false;
 }

 /**
  * 生成一个空的LinkedHashMap,并指定其容量大小,负载因子使用默认的0.75,
  * accessOrder为false表示按照存放顺序来,就是你put元素的时候的顺序
  * accessOrder为true: 表示按照访问的顺序来,也就是谁最先访问,就排在第一位
  */
 public LinkedHashMap(int initialCapacity) {
  super(initialCapacity);
  accessOrder = false;
 }
 /**
  * 生成一个空的HashMap,容量大小使用默认值16,负载因子使用默认值0.75
  * 默认将accessOrder设为false,按插入顺序排序.
  */
 public LinkedHashMap() {
  super();
  accessOrder = false;
 }
 /**
  * 根据指定的map生成一个新的HashMap,负载因子使用默认值,初始容量大小为Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,DEFAULT_INITIAL_CAPACITY)
  * 默认将accessOrder设为false,按插入顺序排序.
  */
 public LinkedHashMap(Map<? extends K, ? extends V> m) {
  super();
  accessOrder = false;
  putMapEntries(m, false);
 }
 /**
  * 生成一个空的LinkedHashMap,并指定其容量大小和负载因子,
  * 默认将accessOrder设为true,按访问顺序排序
  */
 public LinkedHashMap(int initialCapacity,
       float loadFactor,
       boolean accessOrder) {
  super(initialCapacity, loadFactor);
  this.accessOrder = accessOrder;
 }
Nach dem Login kopieren
putMapEntries(m,false) ruft die Methode der übergeordneten Klasse HashMap auf und fügt dann Daten entsprechend dem Put von HashMap ein:


 /**
  * Implements Map.putAll and Map constructor
  *
  * @param m the map
  * @param evict false when initially constructing this map, else
  * true (relayed to method afterNodeInsertion).
  */
 final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
  int s = m.size();
  if (s > 0) {
   if (table == null) { // pre-size
    float ft = ((float)s / loadFactor) + 1.0F;
    int t = ((ft < (float)MAXIMUM_CAPACITY) ?
       (int)ft : MAXIMUM_CAPACITY);
    if (t > threshold)
     threshold = tableSizeFor(t);
   }
   else if (s > threshold)
    resize();
   for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
    K key = e.getKey();
    V value = e.getValue();
    putVal(hash(key), key, value, false, evict);
   }
  }
 }
Nach dem Login kopieren

Speicher:

Die von put aufgerufene Put-Methode von HashMap ruft zwei leere Methoden auf, die von LinkedHashMap implementiert werden


public V put(K key, V value) {
  return putVal(hash(key), key, value, false, true);
 }
Nach dem Login kopieren


final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
     boolean evict) {
  Node<K,V>[] tab; Node<K,V> p; int n, i;
  if ((tab = table) == null || (n = tab.length) == 0)
   n = (tab = resize()).length;
  if ((p = tab[i = (n - 1) & hash]) == null)
   tab[i] = newNode(hash, key, value, null);
  else {
   Node<K,V> e; K k;
   if (p.hash == hash &&
    ((k = p.key) == key || (key != null && key.equals(k))))
    e = p;
   else if (p instanceof TreeNode)
    e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
   else {
    for (int binCount = 0; ; ++binCount) {
     if ((e = p.next) == null) {
      p.next = newNode(hash, key, value, null);
      if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
       treeifyBin(tab, hash);
      break;
     }
     if (e.hash == hash &&
      ((k = e.key) == key || (key != null && key.equals(k))))
      break;
     p = e;
    }
   }
   if (e != null) { // existing mapping for key
    V oldValue = e.value;
    if (!onlyIfAbsent || oldValue == null)
     e.value = value;
    afterNodeAccess(e);
    return oldValue;
   }
  }
  ++modCount;
  if (++size > threshold)
   resize();
  afterNodeInsertion(evict);
  return null;
 }
Nach dem Login kopieren
Der rote Teil in der Hashmap ist eine leere Implementierung:


 void afterNodeAccess(Node<K,V> p) { }
 void afterNodeInsertion(boolean evict) { }
Nach dem Login kopieren
Schauen Sie sich dann an, wie Sie diese beiden Methoden in LinkedHashMap implementieren:

Verschieben Sie den aktuellen Knoten e an das Ende der doppelt verknüpften Liste. Jedes Mal, wenn auf ein Element in LinkedHashMap zugegriffen wird, wird es entsprechend der Reihenfolge des Zugriffs sortiert. Die zuerst aufgerufenen Elemente befinden sich am Anfang der doppelt verknüpften Liste, und die Elemente, auf die später zugegriffen wird, befinden sich näher am Ende. Natürlich wird dieser Vorgang nur ausgeführt, wenn accessOrder wahr ist.


void afterNodeAccess(Node<K,V> e) {
  LinkedHashMap.Entry<K,V> last;
  // 若访问顺序为true,且访问的对象不是尾结点
  if (accessOrder && (last = tail) != e) {
   // 向下转型,记录p的前后结点
   LinkedHashMap.Entry<K,V> p =
    (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
   // p的后结点为空
   p.after = null;
   // 如果p的前结点为空
   if (b == null)
    // a为头结点
    head = a;
   else // p的前结点不为空
    // b的后结点为a
    b.after = a;
   // p的后结点不为空
   if (a != null)
    // a的前结点为b
    a.before = b;
   else // p的后结点为空
    // 后结点为最后一个结点
    last = b;
   // 若最后一个结点为空
   if (last == null)
    // 头结点为p
    head = p;
   else { // p链入最后一个结点后面
    p.before = last;
    last.after = p;
   }
   // 尾结点为p
   tail = p;
   // 增加结构性修改数量
   ++modCount;
  }
 }
Nach dem Login kopieren
Löschen Sie den Kopfknoten der doppelt verknüpften Liste, wenn die Methode „afterNodeInsertion“ wahr ist


 void afterNodeInsertion(boolean evict) { // possibly remove eldest
  LinkedHashMap.Entry<K,V> first;
     //头结点不为空,删除头结点
  if (evict && (first = head) != null && removeEldestEntry(first)) {
   K key = first.key;
   removeNode(hash(key), key, null, false, true);
  }
 }
Nach dem Login kopieren
Löschvorgang Rufen Sie die Remove-Methode von HashMap auf, um Elemente zu löschen, entfernen Sie den Aufruf von RemoveNode und RemoveNode verfügt über eine Methode, für deren Implementierung LinkedHashMap erforderlich ist:

Löschen Sie den E-Knoten aus der doppelt verknüpften Liste und ändern Sie die Referenzbeziehung zwischen die Knoten vor und nach e und verbinden Sie sie erneut. Vervollständigen Sie die doppelt verknüpfte Liste.


 void afterNodeRemoval(Node<K,V> e) { // unlink
  LinkedHashMap.Entry<K,V> p =
   (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
  p.before = p.after = null;
  if (b == null)
   head = a;
  else
   b.after = a;
  if (a == null)
   tail = b;
  else
   a.before = b;
 }
Nach dem Login kopieren
Lesen Sie:

e ist nicht leer, dann ermitteln Sie den Wert von e und geben ihn zurück.


public V get(Object key) {
  Node<K,V> e;
  if ((e = getNode(hash(key), key)) == null)
   return null;
  if (accessOrder)
   afterNodeAccess(e);
  return e.value;
 }
Nach dem Login kopieren
accessOrder ist wahr, was bedeutet, dass der Inhalt in der Reihenfolge des Zugriffs abgerufen wird.


 void afterNodeAccess(Node<K,V> e) {
  LinkedHashMap.Entry<K,V> last;
  // 若访问顺序为true,且访问的对象不是尾结点
  if (accessOrder && (last = tail) != e) {
   // 向下转型,记录p的前后结点
   LinkedHashMap.Entry<K,V> p =
    (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
   // p的后结点为空
   p.after = null;
   // 如果p的前结点为空
   if (b == null)
    // a为头结点
    head = a;
   else // p的前结点不为空
    // b的后结点为a
    b.after = a;
   // p的后结点不为空
   if (a != null)
    // a的前结点为b
    a.before = b;
   else // p的后结点为空
    // 后结点为最后一个结点
    last = b;
   // 若最后一个结点为空
   if (last == null)
    // 头结点为p
    head = p;
   else { // p链入最后一个结点后面
    p.before = last;
    last.after = p;
   }
   // 尾结点为p
   tail = p;
   // 增加结构性修改数量
   ++modCount;
  }
 }
Nach dem Login kopieren
Mehrere Iteratoren von LinkedHashMap:

Abstrakte Klasse LinkedHashIterator implementiert spezifisches Löschen, bestimmt, ob es einen nächsten Knoten gibt, und iteriert die Logik.

LinkedKeyIterator erbt von LinkedHashIterator, implementiert die Iterator-Schnittstelle und iteriert die Schlüssel in LinkedHashMap.

LinkedValueIterator erbt von LinkedHashIterator, implementiert die Iterator-Schnittstelle, iteriert den Wert in LinkedHashMap
LinkedEntryIterator erbt von LinkedHashIterator, implementiert die Iterator-Schnittstelle und iteriert die Knoten in LinkedHashMap


Das obige ist der detaillierte Inhalt vonBeispiel für das Parsen des LinkedHashMap-Quellcodes in Java. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage