总结一下,方便自己查看
按照步骤来:
获取class对象,然后实例化,然后调用实例化对象的哪一个方法或者得到他的哪一个变量。
1. 获取class对象
三种:
Class<?> clazz = Class.forName("com.example.MyClass");
MyClass obj = new MyClass();
Class<?> clazz = obj.getClass();
Class<?> clazz = MyClass.class;
2. 获取方法和字段
api差不多,也可以获取注解等
Field field = clazz.getDeclaredField("xx);
Method get = clazz.getDeclaredMethod("get");
3.调用方法、获取字段值
调用前设置可以访问:field.setAccessible(true)或method.setAccess(true),否则会报错。
调用方法、获取字段值需要实例化对象。
Constructor<?> privateConstructor = clazz.getDeclaredConstructor();
privateConstructor.setAccessible(true);
// 调用构造方法实例化
Object instance = privateConstructor.newInstance();
// 调用方法
Method method = clazz.getMethod("methodName", String.class, int.class);
Object result = method.invoke(instance, "param1", 123);
// 获取字段值
Field privateField = clazz.getDeclaredField("privateFieldName");
privateField.setAccessible(true);
Object value = privateField.get(instance);
如果是静态变量,就不需要实例化对象了。
4.举例
反射获取unsafe对象
unsafe对象不能随便使用。要使用必须反射获取。
class MyClass {
private int state = 0;
private static final long stateOffset;
private static final Unsafe unsafe;
static {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
// 因为是静态变量,不需要实例化
unsafe = (Unsafe)theUnsafe.get(null);
// 获取MyClass中state变量的地址
stateOffset = unsafe.objectFieldOffset(MyClass.class.getDeclaredField("state"));
} catch (Exception e) {
throw new Error(e);
}
}
public static void main(String[] args) throws Exception{
MyClass myClass = new MyClass();
System.out.println(myClass.state);
boolean b = unsafe.compareAndSwapInt(myClass, stateOffset, 0, 1);
if (b) {
System.out.println(myClass.state);
}
}
}
unsafe源码。
我们程序的classloader自然是appclassloader,所以会抛出异常。
@CallerSensitive
public static Unsafe getUnsafe() {
Class var0 = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
throw new SecurityException("Unsafe");
} else {
return theUnsafe;
}
}