**让星星月亮告诉你,通过反射创建类的实例对象,并通过Unsafe theUnsafe来修改实例对象的私有的String类型的成员属性的值**
首先,了解一些Unsafe这个类,这个类可以直接进行内存级别的相关操作(如分配释放内存、修改指定内存地址的值等),这里主要介绍的是用它的theUnsafe私有成员属性来修改指定内存位置的值。
流程如下:
一、 ⭐⭐⭐获取Unsafe theUnsafe属性🌙🌙🌙
1、 通过反射获取Unsafe.class的theUnsafe属性(可以用它来进行内存操作,这里主要是用它来修改指定内存位置的值)
2、 将属性访问权限放开
因为该属性是私有属性,本来外部是无法直接访问的,如果不把属性访问权限放开,则无法获取属性,在执行f.getInt(target)时,
会报错:java.lang.IllegalAccessException: Class thread.mutilthreads_sync.UnsafeTest can not access a member of class java.lang.Integer with modifiers “private final”
3、 获取静态属性值(获取静态属性值的时候,Field的get方法不需要传入具体的实例对象,只需传入null即可,因为静态属性本就不需要实例对象就可以获取)
获取到theUnsafe属性后,后续就可以用它来修改指定内存位置的值
二、 ⭐⭐⭐利用反射创建User类的实例对象user🌙🌙🌙
1、 创建类的class对象
2、 跟据类的class对象,获取类的构造方法(当有多个构造方法时,可以通过指定构造方法的参数类型来区分)
3、 定义预期值
4、 通过获取到的类的构造方法,来创建实例对象
三、 ⭐⭐⭐利用反射获取实例对象user的name属性,并利用theUnsafe直接操作内存地址进行属性值的修改🌙🌙🌙
1、 通过反射获取User类的实例对象target的成员属性name
2、 将User类的实例对象target私有成员属性的访问权限放开
不把属性访问权限放开,则无法获取属性,在执行f.getInt(target)时,
会报错:java.lang.IllegalAccessException: Class thread.mutilthreads_sync.UnsafeTest can not access a member of class java.lang.Integer with modifiers “private final”
但是,即便不放开,也可以利用theUnsafe对该私有成员属性的值进行修改,因为theUnsafe是直接在该属性值所在的内存地址上直接进行修改操作,不受jvm语言层面的访问权限的控制!
3、 获取属性当前值
4、 通过 theUnsafe获取name属性相对于对象实例的偏移量(后面就是利用这个偏移量定位到属性的内存地址的)
5、 定义新值
6、 通过 theUnsafe的compareAndSwapObject方法,进行属性值的修改操作
7、 取被unsafe修改后的属性值
四、⭐⭐⭐代码如下🌙🌙🌙:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import sun.misc.Unsafe;
public class ReflectTest {
private static Unsafe theUnsafe;
static{
try {
// 0 获取theUnsafe
// 00 通过反射获取Unsafe.class的theUnsafe属性(可以用它来进行内存操作,这里主要是用它来修改指定内存位置的值)
Field field = Unsafe.class.getDeclaredField("theUnsafe");
// 01 将属性访问权限放开
// 因为该属性是私有属性,本来外部是无法直接访问的,如果不把属性访问权限放开,则无法获取属性,在执行f.getInt(target)时,
// 会报错:java.lang.IllegalAccessException: Class thread.mutilthreads_sync.UnsafeTest can not access a member of class java.lang.Integer with modifiers "private final"
field.setAccessible(true);
// 02 获取静态属性值(获取静态属性值的时候,Field的get方法不需要传入具体的实例对象,只需传入null即可,因为静态属性本就不需要实例对象就可以获取)
// 获取到theUnsafe属性后,后续就可以用它来修改指定内存位置的值
theUnsafe = (Unsafe)field.get(null);
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
// 1 利用反射创建User类的实例对象user
// 1.1 创建类的class对象(三种方式:①Class.forName("全类名") ②类.class ③实例.getClass())
// Class cls = Class.forName("grammar.User");
Class cls = User.class;
// 1.2 跟据类的class对象,获取类的构造方法(当有多个构造方法时,可以通过指定构造方法的参数类型来区分)
Constructor ctor = cls.getDeclaredConstructor(String.class);
// 1.3 定义预期值
String exceptedValue = "constructor init name";
// 1.4 通过获取到的类的构造方法,来创建实例对象
User target = (User) ctor.newInstance(exceptedValue);
// 2 利用反射获取实例对象user的name属性,并利用theUnsafe直接操作内存地址进行属性值的修改
// 2.1 通过反射获取User类的实例对象target的成员属性name
Field f = target.getClass().getDeclaredField("name");
// 2.2 将User类的实例对象target私有成员属性的访问权限放开
// 不把属性访问权限放开,则无法获取属性,在执行f.getInt(target)时,
// 会报错:java.lang.IllegalAccessException: Class thread.mutilthreads_sync.UnsafeTest can not access a member of class java.lang.Integer with modifiers "private final"
// 但是,即便不放开,也可以利用theUnsafe对该私有成员属性的值进行修改,因为theUnsafe是直接在该属性值所在的内存地址上直接进行修改操作,不受jvm语言层面的访问权限的控制!
f.setAccessible(true);
// 2.3 获取属性当前值
String getNameValue = (String) f.get(target);
System.out.println(getNameValue);//获取user对象的name属性的值
// 2.4 通过 theUnsafe获取name属性相对于对象实例的偏移量(后面就是利用这个偏移量定位到属性的内存地址的)
int offset = (int) theUnsafe.objectFieldOffset(f);//获取
System.out.println("offset:" + offset);
// 2.5 定义新值
String newValue = "unsafe modify name";
// 2.6 通过 theUnsafe的compareAndSwapObject方法,进行属性值的修改操作
boolean result = theUnsafe.compareAndSwapObject(target, offset, exceptedValue, newValue);//当要修改的对象target的offset这个位置的当前值与预期值exceptedValue相同时,则将offset这个位置的值改为新值newValue
System.out.println("result :" + result);
// 2.7 取被unsafe修改后的属性值
System.out.println(f.get(target));
}
}