千家信息网

JDK的LinkedHashMap怎么使用

发表于:2025-01-17 作者:千家信息网编辑
千家信息网最后更新 2025年01月17日,这篇文章主要介绍"JDK的LinkedHashMap怎么使用",在日常操作中,相信很多人在JDK的LinkedHashMap怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对
千家信息网最后更新 2025年01月17日JDK的LinkedHashMap怎么使用

这篇文章主要介绍"JDK的LinkedHashMap怎么使用",在日常操作中,相信很多人在JDK的LinkedHashMap怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"JDK的LinkedHashMap怎么使用"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

  1. package org.corey.demo;


  2. import java.util.HashMap;

  3. import java.util.Iterator;

  4. import java.util.LinkedHashMap;

  5. import java.util.Map;


  6. public class Test {


  7. /**

  8. * @param args

  9. */

  10. public static void main(String[] args) {

  11. Map map = new LinkedHashMap(4);

  12. map.put("1", "corey");

  13. map.put("2", "syna");

  14. map.put("3", "bobo");


  15. Iterator it=map.keySet().iterator();

  16. System.out.println("-------------------------linked hash map----------------------");

  17. while(it.hasNext()){

  18. String key=(String)it.next();

  19. System.out.println(key+":"+map.get(key));

  20. }


  21. Map map2 = new HashMap(4);

  22. map2.put("1", "corey");

  23. map2.put("2", "syna");

  24. map2.put("3", "bobo");


  25. Iterator it2=map2.keySet().iterator();

  26. System.out.println("-------------------------hash map----------------------");

  27. while(it2.hasNext()){

  28. String key=(String)it2.next();

  29. System.out.println(key+":"+map2.get(key));

  30. }


  31. }


  32. }

console:

-------------------------linked hash map----------------------
1:corey
2:syna
3:bobo
-------------------------hash map----------------------
2:syna
1:corey
3:bobo

从而可见,我们的问题得到了解决;

现在我们从LinkEdHashMap代码内部来详细的分析其实现原理;

  1. private transient Entry header;

在LinkedHashMap中含有一个Entry的属性;注意,这个Entry不是上一次我们在HashMap中见到的单向Entry,他被扩充了:

  1. private static class Entry extends HashMap.Entry {

  2. //他有两个指针分别指向了before和after的Entry

  3. //请注意,不要把next和他们混淆了,next的用处还是和HashMap中一//样;

  4. Entry before, after;


  5. Entry(int hash, K key, V value, HashMap.Entry next) {

  6. super(hash, key, value, next);

  7. }



  8. private void remove() {

  9. before.after = after;

  10. after.before = before;

  11. }


  12. //在当前节点前面插入节点;

  13. private void addBefore(Entry existingEntry) {

  14. after = existingEntry;

  15. before = existingEntry.before;

  16. before.after = this;

  17. after.before = this;

  18. }



  19. void recordAccess(HashMap m) {

  20. LinkedHashMap lm = (LinkedHashMap)m;

  21. if (lm.accessOrder) {

  22. lm.modCount++;

  23. remove();

  24. addBefore(lm.header);

  25. }

  26. }


  27. void recordRemoval(HashMap m) {

  28. remove();

  29. }

  30. }

因为LinkedHashMap是继承的HashMap,那么他们的增删改的操作基本一致,只是利用了模板模式具有了不同的实现;
我们来看一下put方法吧;
下面是HashMap的put方法:

  1. public V put(K key, V value) {

  2. if (key == null)

  3. return putForNullKey(value);

  4. int hash = hash(key.hashCode());

  5. int i = indexFor(hash, table.length);

  6. for (Entry e = table[i]; e != null; e = e.next) {

  7. Object k;

  8. if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {

  9. V oldValue = e.value;

  10. e.value = value;

  11. e.recordAccess(this);

  12. return oldValue;

  13. }

  14. }


  15. modCount++;

  16. addEntry(hash, key, value, i);

  17. return null;

  18. }

  1. void addEntry(int hash, K key, V value, int bucketIndex) {

  2. Entry e = table[bucketIndex];

  3. table[bucketIndex] = new Entry(hash, key, value, e);

  4. if (size++ >= threshold)

  5. resize(2 * table.length);

  6. }

在上一节中我们已经详细的分析过了,在LinkedHashMap中被重载的方法是addEntry;

  1. void addEntry(int hash, K key, V value, int bucketIndex) {

  2. createEntry(hash, key, value, bucketIndex);



  3. Entry eldest = header.after;

  4. if (removeEldestEntry(eldest)) {

  5. removeEntryForKey(eldest.key);

  6. } else {

  7. if (size >= threshold)

  8. resize(2 * table.length);

  9. }

  10. }

  1. void createEntry(int hash, K key, V value, int bucketIndex) {

  2. //和以前一样,首先操作了table序列的链表枝条;

  3. HashMap.Entry old = table[bucketIndex];

  4. Entry e = new Entry(hash, key, value, old);

  5. table[bucketIndex] = e;

  6. //关键在于这一步做了什么;我们知道他在header之前插入了Entry;

  7. e.addBefore(header);

  8. size++;

  9. }

Header元素在构造的时候被初始化,记得吗,这个方法是HashMap在构造函数中利用模板模式传下来的

  1. void init() {

  2. header = new Entry(-1, null, null, null);

  3. header.before = header.after = header;

  4. }

开始的时候Header头尾都是指向自身的;

第二步的时候就是被e.addBefore(header);

  1. private void addBefore(Entry existingEntry) {

  2. after = existingEntry;

  3. before = existingEntry.before;

  4. before.after = this;

  5. after.before = this;

  6. }


如果再put那么就是:


我们再来看一看他的keySet是如何得到的:

重载了newKeyIterator() 的方法:

  1. Iterator newKeyIterator() { return new KeyIterator(); }

我们看一下迭代器是如何实现的:

  1. private abstract class LinkedHashIterator implements Iterator {

  2. //从开始的图3我们可见,第一次加入的节点是位于header.after的位置;

  3. Entry nextEntry = header.after;


  4. Entry lastReturned = null;


  5. int expectedModCount = modCount;


  6. //nextnEntry不是header就不是末尾

  7. public boolean hasNext() {

  8. return nextEntry != header;

  9. }


  10. public void remove() {

  11. if (lastReturned == null)

  12. throw new IllegalStateException();

  13. if (modCount != expectedModCount)

  14. throw new ConcurrentModificationException();


  15. LinkedHashMap.this.remove(lastReturned.key);

  16. lastReturned = null;

  17. expectedModCount = modCount;

  18. }


  19. Entry nextEntry() {

  20. if (modCount != expectedModCount)

  21. throw new ConcurrentModificationException();

  22. if (nextEntry == header)

  23. throw new NoSuchElementException();


  24. //指针沿着after往下走

  25. Entry e = lastReturned = nextEntry;

  26. //预先把nextEntry移动到了下一位

  27. nextEntry = e.after;

  28. return e;

  29. }

  30. }


把next方法抽象出去是因为values和keySet的迭代次序是一样的,就是返回的数值不同,所以可以把
Entry的遍历方式推到上层,而values和keys分别留给子类实现;

  1. private class KeyIterator extends LinkedHashIterator {

  2. public K next() { return nextEntry().getKey(); }

  3. }

  4. private class KeyIterator extends LinkedHashIterator {

  5. public K next() { return nextEntry().getKey(); }

  6. }


  7. private class ValueIterator extends LinkedHashIterator {

  8. public V next() { return nextEntry().value; }

  9. }


  10. private class EntryIterator extends LinkedHashIterator> {

  11. public Map.Entry next() { return nextEntry(); }

  12. }

到此,关于"JDK的LinkedHashMap怎么使用"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

0