Java中的LinkedHashMap

Java中的LinkedHashMap

在Java编程中,我们经常需要使用到HashMap,它是一个非常常用的数据结构。用于存储键值对,并且可以根据键快速的查找对应的值。但是HashMap在遍历时是无序的,因为HashMap使用哈希表来存储数据,哈希表并不保证元素的顺序。如果需要有序的遍历,就可以使用LinkedHashMap,它是HashMap的一个子类,除了具备HashMap的所有特性外,还可以保证插入顺序或者访问顺序。

LinkedHashMap的使用

LinkedHashMap类定义了两种运行模式:插入顺序和访问顺序。默认情况下,LinkedHashMap是以插入顺序运行的,即保持元素的插入顺序,当指定accessOrder=true时,LinkedHashMap将按访问顺序运行,即元素被访问的顺序。

下面是一个使用LinkedHashMap的例子:

import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHashMapExample {
    public static void main(String[] args) {
        LinkedHashMap<String, String> linkedHashMap = new LinkedHashMap<>();
        linkedHashMap.put("1", "One");
        linkedHashMap.put("2", "Two");
        linkedHashMap.put("3", "Three");
        linkedHashMap.put("4", "Four");
        linkedHashMap.put("5", "Five");

        for (Map.Entry<String, String> entry : linkedHashMap.entrySet()) {
            System.out.println(entry.getKey() + " = " + entry.getValue());
        }
    }
}

输出结果为:

1 = One
2 = Two
3 = Three
4 = Four
5 = Five

可以看到输出的顺序与插入的顺序一致。如果我们将LinkedHashMap中的元素访问一遍,再进行输出,则输出的顺序将会变为访问的顺序。

import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHashMapExample {
    public static void main(String[] args) {
        LinkedHashMap<String, String> linkedHashMap = new LinkedHashMap<>(16, 0.75f, true); // accessOrder=true
        linkedHashMap.put("1", "One");
        linkedHashMap.put("2", "Two");
        linkedHashMap.put("3", "Three");
        linkedHashMap.put("4", "Four");
        linkedHashMap.put("5", "Five");

        linkedHashMap.get("1"); // 访问1
        linkedHashMap.get("3"); // 访问3

        for (Map.Entry<String, String> entry : linkedHashMap.entrySet()) {
            System.out.println(entry.getKey() + " = " + entry.getValue());
        }
    }
}

输出结果为:

2 = Two
4 = Four
5 = Five
1 = One
3 = Three

可以看到输出的顺序已经不再是插入的顺序,而是访问的顺序。

如何在LinkedHashMap中实现LRU缓存

LRU是Least Recently Used的缩写,即最近最少使用算法。在缓存淘汰策略中,会优先淘汰最近最少被使用的数据,而保留最常用的数据。在LinkedHashMap中,通过accessOrder=True可以实现按照访问顺序来运行,因此可以用LinkedHashMap来实现LRU缓存。

下面是一个简单的实现LRU缓存的例子:

import java.util.LinkedHashMap;
import java.util.Map;

class LRUCache<K, V> extends LinkedHashMap<K, V> {
    private final int cacheSize;

    public LRUCache(int cacheSize) {
        super((int) Math.ceil(cacheSize / 0.75f) + 1, 0.75f, true); // accessOrder=true
        this.cacheSize = cacheSize;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        return size() > cacheSize;
    }
}

public class LRUCacheExample {
    public static void main(String[] args) {
        LRUCache<String, String> cache = new LRUCache<>(3);
       cache.put("1", "One");
        cache.put("2", "Two");
        cache.put("3", "Three");
        System.out.println(cache); // 输出:{1=One, 2=Two, 3=Three}

        cache.get("2");
        System.out.println(cache); // 输出:{1=One, 3=Three, 2=Two}

        cache.put("4", "Four");
        System.out.println(cache); // 输出:{3=Three, 2=Two, 4=Four}

        cache.put("5", "Five");
        System.out.println(cache); // 输出:{2=Two, 4=Four, 5=Five}
    }
}

在LRUCache类中,我们继承了LinkedHashMap,重写了其removeEldestEntry方法。该方法会在每次put操作后被调用,如果返回true,则移除第一个元素,否则继续保留。在LRUCache构造函数中,我们指定了accessOrder=true,因此LinkedHashMap会按照访问顺序来保存元素。

在LRUCacheExample中,我们首先插入了三个元素1、2、3,此时LinkedHashMap中保存的顺序是1、2、3。然后我们访问了元素2,此时LinkedHashMap中的顺序变为1、3、2。然后插入了元素4,LinkedHashMap中的顺序变为3、2、4,因为元素1是最早插入的,同时最近没有被访问,因此被移除了。最后插入元素5,LinkedHashMap中保留的元素为2、4、5,因为元素3已经被访问过,但是比元素1晚插入,因此被移除了。

结论

LinkedHashMap是HashMap的一个子类,除了具备HashMap的所有特性外,还可以保证插入顺序或者访问顺序。可以用LinkedHashMap来实现LRU缓存。在LinkedHashMap中,通过accessOrder=True可以实现按照访问顺序来运行。在LRUCache中,我们继承了LinkedHashMap,重写了其removeEldestEntry方法,该方法会在每次put操作后被调用,如果返回true,则移除第一个元素,否则继续保留。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程