java 反射
总结一下,方便自己查看
按照步骤来:
获取class对象,然后实例化,然后调用实例化对象的哪一个方法或者得到他的哪一个变量。
文章目录
- 1. 获取class对象
- 2. 获取方法和字段
- 3.调用方法、获取字段值
- 4.举例
- 反射获取unsafe对象
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,所以会抛出异常。
@CallerSensitivepublic static Unsafe getUnsafe() {Class var0 = Reflection.getCallerClass();if (!VM.isSystemDomainLoader(var0.getClassLoader())) {throw new SecurityException("Unsafe");} else {return theUnsafe;}}