美文网首页
Unsafe的一次使用

Unsafe的一次使用

作者: 哇_李荣 | 来源:发表于2018-08-18 16:48 被阅读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
    

    相关文章

      网友评论

          本文标题:Unsafe的一次使用

          本文链接:https://www.haomeiwen.com/subject/ixvfiftx.html