之前公司在消费MQ的时候,保存了最近消费100条消息的ID,用于去重,想着应该是这种思想实现的,java LinkedHashMap有自带的这种功能,今天试着自己写一个,借助HashMap来实现。
做个笔记,学习学习
1.LinkedHashMap
我这儿说的比较简单,要深入理解的话,还得熟悉数据结构和查看源码!
public static void main(String[] args) {
/**
* LinkedHashMap继承了HashMap,LinkedHashMap内部维护了一个链表
* 我们向LinkedHashMap添加、删除、查询一个KV时
* 其实调用的是HashMap的put、remove、get 方法
* 通过源码HashMap源码可以看到,调用这些方法后
* 会调用对应的方法,在HashMap里面是空方法体
* void afterNodeAccess(Node<K,V> p) { }
* void afterNodeInsertion(boolean evict) { }
* void afterNodeRemoval(Node<K,V> p) { }
* 这几个就是在LinkedHashMap里面实现了的方法
* 比如LinkedHashMap源码:
* 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);
* }
* }
* 可以看到if里面有一个条件removeEldestEntry(first) 需要为true,就会remove一个head(first)
* 但是LinkedHashMap里面这个方法默认为false,所以可以在构造器里面重新这个方法
* 在插入一个节点后,当满足我们指定的条件时,就会把链表的head(first)节点删除掉,实现LRU
*/
int cacheSize = 100;
Map<String, String> map = new LinkedHashMap<String, String>
(cacheSize, (float) 0.75, true){
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
//满足这个条件时,就会删除第一个节点啦
return size()>cacheSize;
}
};
//LruLinkedMap<String, String> map = new LruLinkedMap<>();
map.put("a","aa");
}
2.自已借助HashMap 简单实现一个
/**
* 来个自己的Node节点接口,也可以实现Map.Entry<K,V>
* 但是用Map.Entry,debug的时候,可能看不到想看的一些信息?
*/
public interface MyNode <K,V>{
K getKey();
V getValue();
}
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class LruLinkedMap<K,V> implements Iterable<MyNode<K,V>>{
private final Map<K,Node<K,V>> hashMap;
private int size;
private Node<K,V> head, tail;
private static final int DEFAULT_CAPACITY = 1 << 4; //16
public LruLinkedMap() {
this(DEFAULT_CAPACITY);
}
public LruLinkedMap(int capacity) {
this.hashMap = new HashMap<>(capacity);
this.size = 0;
this.head = this.tail = null;
}
public int size(){
return size;
}
/**
* 获取map里面的Node里面的value
* @param key key 不为空
* @return value
*/
public V get(K key){
Node<K,V> node = hashMap.get(key);
if(node != null){
afterNodeAccess(node);
return node.value;
}
return null;
}
/**
* 把node放入map,如果key存在就更新node,如果不存在就新建一个node
* @param key key
* @param value value
* @return 返回上次存在的value
*/
public V put(K key, V value){
//如果已经存在该key
Node<K,V> node = hashMap.get(key);
if(node != null){
node.value = value;
node = hashMap.put(key, node);
afterNodeAccess(node);
return node == null ? null : node.value;
}
//如果不存在key
node = newNode(key, value, tail);
hashMap.put(key, node);
size = hashMap.size();
afterNodeInsert(node);
return null;
}
/**
*
* @param key key
* @return node
*/
public Node<K,V> remove(K key){
//如果存在
Node<K,V> node = hashMap.remove(key);
if(node != null){
size = hashMap.size();
afterNodeRemove(node);
}
//如果不存在
return node;
}
/**
* 操作节点后,把节点移动到最后
* @param node 当前节点
*/
private void afterNodeAccess(Node<K,V> node) {
//如果node为头节点
if(head == node){
//如果head.nextNode == null 说明 只有一个节点(头结点)
if(head.nextNode != null){
head = head.nextNode;
head.preNode = null;
tail.nextNode = node;
node.preNode = tail;
tail = node;
}
}else if(tail != node){
//如果node为尾节点,就不用移动节点了
Node<K,V> pre = node.preNode;
Node<K,V> next = node.nextNode;
//...pre(p,node) node(pre,next) next(node,n4)...tail(x,null)
pre.nextNode = next;
//...pre(p,node->next) node(pre,next) next(node,n4)...tail(x,null)
next.preNode = pre;
//...pre(p,next) node(pre,next) next(node->pre,n4)...tail(x,null)
node.nextNode = null;
//...pre(p,next) node(pre,next->null) next(node->pre,n4)...tail(x,null)
node.preNode = tail;
//...pre(p,next) node(pre->tail,null) next(node->pre,n4)...tail(x,null)
tail.nextNode = node;
//...pre(p,next) node(tail,null) next(pre,n4)...tail(x,null->node)
tail = node;
//...pre(p,next) next(pre,n4)...tail(x,node) node(tail,null)
}
}
/**
* 有新的节点插入到map时,更新尾巴tail
* @param newNode 新节点
*/
private void afterNodeInsert(Node<K,V> newNode) {
if(head == null){
head = newNode;
tail = head;
}else {
tail.nextNode = newNode;
tail = newNode;
}
}
/**
*
* @param node 当前节点
*/
private void afterNodeRemove(Node<K, V> node) {
//如果是头结点或者seize()==1 两种情况
if(head == node){
if((head = head.nextNode) != null){
head.preNode = null;
}
}else if(tail == node){
//不存在tail.preNode == null
tail = tail.preNode;
tail.nextNode = null;
}else{
Node<K,V> pre = node.preNode;
Node<K,V> next = node.nextNode;
pre.nextNode = next;
next.preNode = pre;
}
}
//返回一个新的Node节点
private Node<K,V> newNode(K key, V value, Node<K,V> preNode){
return new Node<>(key, value, preNode, null);
}
@Override
public Iterator<MyNode<K, V>> iterator() {
return new NodeIterator();
}
final class NodeIterator implements Iterator<MyNode<K,V>>{
private Node<K,V> node;
private NodeIterator() {
this.node = head;
}
@Override
public boolean hasNext() {
return node != null;
}
@Override
public MyNode<K, V> next() {
Node<K,V> n = node;
node = node.nextNode;
return n;
}
}
/**
* implements {@link Map.Entry}, base node
* @param <K>
* @param <V>
*/
static class Node<K,V> implements MyNode<K,V>{
final K key;
V value;
Node<K,V> preNode;
Node<K,V> nextNode;
Node(K key, V value, Node<K, V> preNode, Node<K, V> nextNode) {
this.key = key;
this.value = value;
this.preNode = preNode;
this.nextNode = nextNode;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
public V setValue(V newValue) {
V oldValue = this.value;
this.value = newValue;
return oldValue;
}
}
}