Python微信订餐小程序课程视频
https://edu.csdn.net/course/detail/36074
Python实战量化交易理财系统
https://edu.csdn.net/course/detail/35475
目录* 0 前言
0 前言
unsafe里面有很多好用的方法,比如allocateInstance可以直接创建实例对象,defineAnonymousClass可以创建一个VM匿名类(VM Anonymous Class),以及直接从内存级别修改对象的值。
1 基本使用
首先是获取Unsafe对象,一般使用反射获取Unsafe,否则会被Java安全机制拦截,代码如下
public static Unsafe getUnsafe() throws Exception{
Class aClass = Class.forName("sun.misc.Unsafe");
Constructor declaredConstructor = aClass.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
Unsafe unsafe= (Unsafe) declaredConstructor.newInstance();
return unsafe;
}
1.1 内存级别修改值
这里首先要提到的是,在jvm中,对实例的Field进行了有规律的存储,具体可见JVM相关知识,而通过一个偏移量可以从内存中找到相应的Field值。在Unsafe中获取偏移量的方法是staticFieldOffset(Field var1)和objectFieldOffset(Field var1)这两个方法,输入一个Field对象后,会返回该Field在其相应的类中的内存偏移量是多少。通过获得的偏移量可进一步调用putInt、putLong、putObject等方法对实例的field进行修改。
例如:
package com.bitterz.unsafe;
import sun.misc.Unsafe;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class UnsafeTest {
private int a = 1;
private String string = "whoami";
public UnsafeTest(){}
public void test(){ }
public static void main(String[] args) throws Exception {
Unsafe unsafe = getUnsafe();
UnsafeTest unsafeTest = new UnsafeTest();
// 修改int
Field f = Class.forName("com.bitterz.unsafe.UnsafeTest").getDeclaredField("a");
long l = unsafe.objectFieldOffset(f);
unsafe.putInt(unsafeTest, l, 9999);
System.out.println(unsafeTest.a);
// 修改string
Field f2 = Class.forName("com.bitterz.unsafe.UnsafeTest").getDeclaredField("string");
long l2 = unsafe.objectFieldOffset(f2);
unsafe.putObject(unsafeTest, l2, "bitterz");
System.out.println(unsafeTest.string);
}
public static Unsafe getUnsafe() throws Exception{
Class aClass = Class.forName("sun.misc.Unsafe");
Constructor declaredConstructor = aClass.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
Unsafe unsafe= (Unsafe) declaredConstructor.newInstance();
return unsafe;
}
}
其输出结果为
但对final和static修饰的field这种修改方法无效。另外还可以通过偏移量使用getInt()、getObject()等方法获取实例的field值,这种方法也可以作为反射被限制时的一种绕过。
1.2 创建对象
Unsafe中有个allocateInstance方法,可以无视构造方法,直接利用类对象构建实例,这种方法往往能够减少反射创建实例时可能遇到的各种阻碍,比如类的依赖关系。
比如前面创建Unsafe时使用了反射,不能直接进行创建,那么可以使用unsafe进行创建(