Java Unsafe获取对象内存地址,对象成员变量相对对象内存地址偏移量以及通过这种方式获取对象成员变量的值
UnsafeTestKlass
public class UnsafeTestKlass {
private int value;
public UnsafeTestKlass() { this(99); }
public UnsafeTestKlass(int value) { this.value = value; }
public int value() { return value; } } |
获取对象内存地址
public long location(Object object) throws Throwable { Unsafe unsafe = getUnsafe();
Object[] array = new Object[] {object};
long baseOffset = unsafe.arrayBaseOffset(Object[].class); int addressSize = unsafe.addressSize(); long location; switch (addressSize) { case 4: location = unsafe.getInt(array, baseOffset); break; case 8: location = unsafe.getLong(array, baseOffset); break; default: throw new Error("unsupported address size: " + addressSize); } return (location); } |
获取Unsafe
private Unsafe getUnsafe() throws Throwable { Class<?> unsafeClass = Unsafe.class; for (Field f : unsafeClass.getDeclaredFields()) { if ("theUnsafe".equals(f.getName())) { f.setAccessible(true); return (Unsafe) f.get(null); } } throw new IllegalAccessException("no declared field: theUnsafe"); } |
例子
/** * here are three way to get the field value of an object: * 1: reflection * 2: address offset of field base object * 3: absolute address of the field of object: * address of object + address offset of field base object * * @throws Throwable */ @Test public void getObjectFieldValue() throws Throwable { UnsafeTestKlass klass = new UnsafeTestKlass();
Field field = UnsafeTestKlass.class.getDeclaredField("value"); field.setAccessible(true); int value1 = (Integer) field.get(klass); System.out.println("value1: " + value1);
Assert.assertTrue(value1 == klass.value());
Unsafe unsafe = getUnsafe(); long valueOffset = unsafe.objectFieldOffset(field); System.out.println("value offset: " + valueOffset); int value2 = unsafe.getInt(klass, valueOffset); System.out.println("value2: " + value2);
Assert.assertTrue(value1 == value2);
long baseAddress = location(klass); System.out.println("base address: " + baseAddress); int value3 = unsafe.getInt(baseAddress + valueOffset); System.out.println("value3: " + value3); Assert.assertTrue(value1 == value3); } |