📅  最后修改于: 2023-12-03 14:42:14.407000             🧑  作者: Mango
Java中的HashMap是一种常用的数据结构,它能够高效地存储和检索键值对。但是,HashMap默认是不会维护插入顺序的,也就是说,随着元素的插入,元素在HashMap中的顺序可能会发生变化。这可能会导致一些问题,比如读取数据时顺序不一致等。所以很多情况下,我们需要在HashMap中维护元素的插入顺序。
Java 8及以上版本提供了一个新的数据结构 LinkedHashMap
,顾名思义,它是一个链表结构的哈希表,在HashMap的基础上额外维护了元素的插入顺序。因此,如果我们需要维护元素的插入顺序,只需要使用LinkedHashMap即可。示例代码如下:
Map<String, Integer> linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put("apple", 1);
linkedHashMap.put("banana", 2);
linkedHashMap.put("orange", 3);
linkedHashMap.forEach((k, v) -> System.out.println(k + ":" + v));
// 输出:apple:1 banana:2 orange:3
对于Java 7及以下版本,我们可以自己实现一个类似于LinkedHashMap的数据结构,即一个哈希表和一个链表的结合体。在插入时,记录元素的插入位置,以便后续可以按照插入顺序访问元素。关键点是需要在插入、删除、遍历等操作时维护链表结构。示例代码如下:
import java.util.HashMap;
public class LinkedHashMap<K, V> extends HashMap<K, V> {
private Entry<K, V> head;
private Entry<K, V> tail;
@Override
public V put(K key, V value) {
V oldValue = super.put(key, value);
Entry<K, V> entry = new Entry<>(key, value);
if (oldValue == null) {
// 新增元素
if (head == null) {
head = entry;
tail = entry;
} else {
tail.next = entry;
entry.prev = tail;
tail = entry;
}
} else {
// 修改元素
Entry<K, V> oldEntry = findEntry(key);
oldEntry.value = value;
}
return oldValue;
}
@Override
public void clear() {
super.clear();
head = null;
tail = null;
}
@Override
public boolean remove(Object key, Object value) {
boolean removed = super.remove(key, value);
if (removed) {
removeEntry(key);
}
return removed;
}
@Override
public V remove(Object key) {
V value = super.remove(key);
if (value != null) {
removeEntry(key);
}
return value;
}
@Override
public boolean remove(Object key, Object value, int hash, Object keyValHash) {
boolean removed = super.remove(key, value, hash, keyValHash);
if (removed) {
removeEntry(key);
}
return removed;
}
@Override
public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
super.replaceAll(function);
Entry<K, V> entry = head;
while (entry != null) {
entry.value = function.apply(entry.key, entry.value);
entry = entry.next;
}
}
@Override
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
V value = super.computeIfAbsent(key, mappingFunction);
if (value != null) {
Entry<K, V> entry = findEntry(key);
if (entry.value == null) {
entry.value = value;
}
}
return value;
}
@Override
public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
V value = super.computeIfPresent(key, remappingFunction);
if (value != null) {
Entry<K, V> entry = findEntry(key);
if (entry.value != null) {
entry.value = value;
}
}
return value;
}
@Override
public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
V value = super.compute(key, remappingFunction);
if (value != null) {
Entry<K, V> entry = findEntry(key);
if (entry.value != null) {
entry.value = value;
}
}
return value;
}
@Override
public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
V mergedValue = super.merge(key, value, remappingFunction);
if (mergedValue != null) {
Entry<K, V> entry = findEntry(key);
if (entry.value != null) {
entry.value = mergedValue;
}
}
return mergedValue;
}
@Override
public void forEach(BiConsumer<? super K, ? super V> action) {
Entry<K, V> entry = head;
while (entry != null) {
action.accept(entry.key, entry.value);
entry = entry.next;
}
}
private Entry<K, V> findEntry(K key) {
for (Entry<K, V> entry = head; entry != null; entry = entry.next) {
if (Objects.equals(key, entry.key)) {
return entry;
}
}
return null;
}
private void removeEntry(Object key) {
Entry<K, V> entry = findEntry((K) key);
if (entry != null) {
if (entry.prev == null) {
head = entry.next;
} else {
entry.prev.next = entry.next;
}
if (entry.next == null) {
tail = entry.prev;
} else {
entry.next.prev = entry.prev;
}
entry.prev = null;
entry.next = null;
}
}
private static class Entry<K, V> {
final K key;
V value;
Entry<K, V> prev;
Entry<K, V> next;
Entry(K key, V value) {
this.key = key;
this.value = value;
}
}
}
使用时,与普通HashMap类似,直接创建一个LinkedHashMap
实例即可。
在Java中,如果需要维护HashMap中元素的插入顺序,可以使用Java 8及以上版本提供的LinkedHashMap
,或者自己实现一个类似于LinkedHashMap
的数据结构。选择哪种方案,需要根据实际情况进行权衡。