一.获取Unsafe,通用的办法利用
反射机制
class="java" name="code">
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
二.Unsafe自己对调用者的检查
public static Unsafe getUnsafe() {
Class cc = sun.reflect.Reflection.getCallerClass(2);
if (cc.getClassLoader() != null)
throw new SecurityException("Unsafe");
return theUnsafe;
}
getCallerClass调用栈帧,从0开始。
0:getCallerClass方法的Reflection类;
1:getUnsafe方法的Unsafe类;
2:调用getUnsafe方法的所属类
比如:
public static void main(String[] args) throws Exception {
Class cc = sun.reflect.Reflection.getCallerClass(1);
//0:getCallerClass方法的Reflection类,1:main方法的所属类
}
cc.getClassLoader()!= null 用于判断类加载器是否是bootstrap classloader。
1.Bootstrap ClassLoader - GetClassLoader的返回值为Null,是
JVM的C++源码,Ext ClassLoader 的Parent,主要负责jdk_home/lib目录下的核心 api 或 -Xbootclasspath 选项指定的jar包装入工作;
2.System ClassLoader - GetClassLoader返回值为SystemClassLoader.
主要负责java -classpath/-Djava.class.path所指的目录下的类与jar包装入工作
3.Ext ClassLoader - 是AppClassLoader 的Parent 返回Ext ClassLoader
主要负责jdk_home/lib/ext目录下的jar包或-Djava.ext.dirs 指定目录下的jar包装入工作。
4.App ClassLoader - 返回AppClassLoader,主要负责加载用户类。
(后续在继续分析ClassLoader机制)
三:public native int getInt(Object o, long offset);
注释中提到三种情况
第一种场景:The offset was obtained from {@link #objectFieldOffset} on the {@link java.lang.reflect.Field} of some Java field and the object referred to by <code>o</code> is of a class compatible with that field's class.
private int offset = 10;
public static void main(String[] args) throws Exception {
long fieldOffset = unsafe.objectFieldOffset(Main.class.getDeclaredField("offset")) ;
int fieldValue = unsafe.getInt(new Main(), fieldOffset);
}
第二种场景:The offset and object reference <code>o</code> (either null or non-null) were both obtained via{@link #staticFieldOffset} and {@link #staticFieldBase} (respectively) from the reflective {@link Field} representation of some Java field.
private static int staticoffset = 20;
public static void main(String[] args) throws Exception {
Field staticField = Main.class.getDeclaredField("staticoffset");
long staticFieldOffset = unsafe.staticFieldOffset(staticField);
Object obj = unsafe.staticFieldBase(staticField);
int staticFieldValue =unsafe.getInt(obj, staticFieldOffset);
}
第三种场景:The object referred to by <code>o</code> is an array, and the offset is an integer of the form <code>B+N*S</code>, where <code>N</code> is a valid index into the array, and <code>B</code> and <code>S</code> are the values obtained by {@link #arrayBaseOffset} and {@link #arrayIndexScale} (respectively) from the array's class. The value referred to is the <code>N</code><em>th</em> element of the array.
public static void main(String[] args) throws Exception {
int [] intarray = new int[3];
intarray[0] = 10; intarray[1] = 20; intarray[2] = 30;
int arrayOffset = unsafe.arrayBaseOffset(intarray.getClass());
int arrayScale = unsafe.arrayIndexScale(intarray.getClass());
long lg = arrayOffset + 2 * arrayScale;
int arrayValue = unsafe.getInt(intarray, lg);
}