创建目标对象
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 sun.misc.Launcher$AppClassLoader@73d16e93
使用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; }