• 周日. 11月 27th, 2022

5G编程聚合网

5G时代下一个聚合的编程学习网

热门标签

unsafe中方法的使用

admin

11月 28, 2021

创建目标对象

    static class Simple{
        private long l = 0;
        
        public Simple() {
            this.l = 1;
            System.out.println("==================");
        }
        
        public long get() {
            return this.l;
        }
    }

创建对象实例的三种方法

方法一:

Simple simple1 = new Simple();
System.out.println(simple1.get());

方法二:

        Simple simple2 = Simple.class.newInstance();
        System.out.println(simple2.get());

方法三:

        //绕过了类的初始化阶段
        Class<?> simple3 = Class.forName("com.dwz.atomicApi.UnsafeFooTest$Simple");

创建unsafe:

    private static Unsafe getUnsafe() {
        try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            return (Unsafe) f.get(null);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } 
    }

使用unsafe来绕过构造方法创建对象:

        Unsafe unsafe = getUnsafe();
        //开辟内存
        Simple simple4 = (Simple)unsafe.allocateInstance(Simple.class);
        System.out.println(simple4.get());
        System.out.println(simple4.getClass());
        System.out.println(simple4.getClass().getClassLoader());

结果如下:

0
class com.dwz.atomicApi.UnsafeFooTest$Simple
[email protected]

使用unsafe的方式给类的字段赋值

目标对象:

    static class Guard{
        private int ACCESS_ALLOWED = 1;
        
        private boolean allow() {
            return 42 == ACCESS_ALLOWED;
        }
        
        public void work() {
            if(allow()) {
                System.out.println("I am working by allowed.");
            }
        }
    }

测试方法:

        Unsafe unsafe = getUnsafe();
        Guard guard = new Guard();
        
        Field f = guard.getClass().getDeclaredField("ACCESS_ALLOWED");
        unsafe.putInt(guard, unsafe.objectFieldOffset(f), 42);
        guard.work();

测试结果:

I am working by allowed.

使用unsafe读取.class文件

目标对象A.class

package com.dwz.atomicApi;

public class A {
    private int i = 0;
    
    public A() {
        this.i = 1;
    }
    
    public int get() {
        return this.i;
    }
}
    /**
     *     将要加载的文件读到字节数组中去
     * @throws IOException 
     */
    private static byte[] loadClassContent() throws IOException {
        File f = new File("E:\mySoftware\eclipse-workspace\concurrency\target\classes\com\dwz\atomicApi\A.class");
        FileInputStream fis = new FileInputStream(f);
        byte[] content = new byte[(int)f.length()];
        fis.read(content);
        fis.close();
        return content;
    }

测试方法:

        Unsafe unsafe = getUnsafe();
        //该方式也会进行初始化
        byte[] bytes = loadClassContent();
        Class aClass = unsafe.defineClass(null, bytes, 0, bytes.length, null, null);
        int v = (int)aClass.getMethod("get", null).invoke(aClass.newInstance(), null);
        System.out.println(v);

使用unsafe自定义一个sizeOf方法:

    public static long sizeOf(Object obj) {
        Unsafe unsafe = getUnsafe();
        Set<Field> fields = new HashSet<Field>();
        Class c = obj.getClass();
        while(c != Object.class) {
            Field[] declareedFields = c.getDeclaredFields();
            for(Field f : declareedFields) {
                if((f.getModifiers() & Modifier.STATIC) == 0) {
                    fields.add(f);
                }
            }
            
            c = c.getSuperclass();
        }
        
        long maxOffSet = 0;
        for(Field f : fields) {
            long offset = unsafe.objectFieldOffset(f);
            if(offset > maxOffSet) {
                maxOffSet = offset;
            }
        }
        
        return ((maxOffSet/8)+1)*8;
    }

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注