看LinkedHashMap源码的时候,不理解构造函数LinkedHashMap<String, String> lkMap = new LinkedHashMap<>(4, 0.75f, true);
为什么要传三个参数。想着只传accessOrder不是就能达到目的了?接着想到运行时直接修改了accessOrder值也能达到目的。于是就写了下面这段代码。
LinkedHashMap<String, String> map = new LinkedHashMap<>();
Unsafe unsafe = getUnsafe();
Class c = map.getClass();
Field f = c.getDeclaredField("accessOrder");
long flong = unsafe.objectFieldOffset(f);
unsafe.putBoolean(map, flong, true);
map.put("tom", "apple");
map.put("jerry", "orange");
map.put("amy", "banana");
map.get("jerry");
map.put("james", "pear");
map.forEach((o, v) -> System.out.println(o + "->" + v));
output:
tom->apple
amy->banana
jerry->orange
james->pear
使用默认构造函数创建map对象,再使用Unsafe方法访问map对象,修改accessOrder的取值。从输出结果看出,此时map记录的是访问顺序。相对的,如果没有修改accessOrder的话,上面的程序输出结果如下:
output:
tom->apple
jerry->orange
amy->banana
james->pear
输出内容是元素的插入顺序。
需要注意的是,官方不推荐使用Unsafe方法。如果直接调用Unsafe.getUnsafe()
方法,会抛出java.lang.SecurityException
异常。不过这个问题通过反射可以绕过。代码如下:
public static Unsafe getUnsafe() {
try {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
return (Unsafe)f.get(null);
} catch (Exception e) {
/* ... */
}
}
除了用上面的Unsafe类之外,用反射也能达到目的:
LinkedHashMap<String, String> map = new LinkedHashMap<>();
Class c = map.getClass();
Field f = c.getDeclaredField("accessOrder");
f.setAccessible(true);
f.set(map, true);
map.put("tom", "apple");
map.put("jerry", "orange");
map.put("amy", "banana");
map.get("jerry");
map.put("james", "pear");
map.forEach((o, v) -> System.out.println(o + "->" + v));
output:
tom->apple
amy->banana
jerry->orange
james->pear
网友评论