Unsafe的一次使用

2018-08-18  本文已影响0人  哇_李荣

看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
上一篇 下一篇

猜你喜欢

热点阅读