@@ -304,6 +304,49 @@ public boolean validate(long stamp) {
304304
305305#### 介绍
306306
307+ ** 例子**
308+
309+ ``` java
310+ import sun.misc.Unsafe ;
311+ import java.lang.reflect.Field ;
312+
313+ public class Main {
314+
315+ private int value;
316+
317+ public static void main (String [] args ) throws Exception {
318+ Unsafe unsafe = reflectGetUnsafe();
319+ assert unsafe != null ;
320+ long offset = unsafe. objectFieldOffset(Main . class. getDeclaredField(" value" ));
321+ Main main = new Main ();
322+ System . out. println(" value before putInt: " + main. value);
323+ unsafe. putInt(main, offset, 42 );
324+ System . out. println(" value after putInt: " + main. value);
325+ System . out. println(" value after putInt: " + unsafe. getInt(main, offset));
326+ }
327+
328+ private static Unsafe reflectGetUnsafe () {
329+ try {
330+ Field field = Unsafe . class. getDeclaredField(" theUnsafe" );
331+ field. setAccessible(true );
332+ return (Unsafe ) field. get(null );
333+ } catch (Exception e) {
334+ e. printStackTrace();
335+ return null ;
336+ }
337+ }
338+
339+ }
340+ ```
341+
342+ 输出结果:
343+
344+ ```
345+ value before putInt: 0
346+ value after putInt: 42
347+ value after putInt: 42
348+ ```
349+
307350** 对象属性**
308351
309352对象成员属性的内存偏移量获取,以及字段属性值的修改,在上面的例子中我们已经测试过了。除了前面的` putInt ` 、` getInt ` 方法外,Unsafe 提供了全部 8 种基础数据类型以及` Object ` 的` put ` 和` get ` 方法,并且所有的` put ` 方法都可以越过访问权限,直接修改内存中的数据。阅读 openJDK 源码中的注释发现,基础数据类型和` Object ` 的读写稍有不同,基础数据类型是直接操作的属性值(` value ` ),而` Object ` 的操作则是基于引用值(` reference value ` )。下面是` Object ` 的读写方法:
@@ -580,7 +623,7 @@ unpark mainThread success
580623public native long staticFieldOffset(Field f);
581624// 获取静态属性的对象指针
582625public native Object staticFieldBase(Field f);
583- // 判断类是否需要实例化 (用于获取类的静态属性前进行检测)
626+ // 判断类是否需要初始化 (用于获取类的静态属性前进行检测)
584627public native boolean shouldBeInitialized(Class<?> c);
585628```
586629
@@ -594,6 +637,11 @@ public class User {
594637}
595638private void staticTest() throws Exception {
596639 User user= new User ();
640+ // 也可以用下面的语句触发类初始化
641+ // 1.
642+ // unsafe.ensureClassInitialized(User.class);
643+ // 2.
644+ // System.out.println(User.name);
597645 System . out. println(unsafe. shouldBeInitialized(User . class));
598646 Field sexField = User . class. getDeclaredField(" name" );
599647 long fieldOffset = unsafe. staticFieldOffset(sexField);
@@ -611,7 +659,7 @@ falseHydra
611659
612660在 ` Unsafe ` 的对象操作中,我们学习了通过` objectFieldOffset ` 方法获取对象属性偏移量并基于它对变量的值进行存取,但是它不适用于类中的静态属性,这时候就需要使用` staticFieldOffset ` 方法。在上面的代码中,只有在获取` Field ` 对象的过程中依赖到了` Class ` ,而获取静态变量的属性时不再依赖于` Class ` 。
613661
614- 在上面的代码中首先创建一个` User ` 对象,这是因为如果一个类没有被实例化 ,那么它的静态属性也不会被初始化,最后获取的字段属性将是` null ` 。所以在获取静态属性前,需要调用` shouldBeInitialized ` 方法,判断在获取前是否需要初始化这个类。如果删除创建 User 对象的语句,运行结果会变为:
662+ 在上面的代码中首先创建一个` User ` 对象,这是因为如果一个类没有被初始化 ,那么它的静态属性也不会被初始化,最后获取的字段属性将是` null ` 。所以在获取静态属性前,需要调用` shouldBeInitialized ` 方法,判断在获取前是否需要初始化这个类。如果删除创建 User 对象的语句,运行结果会变为:
615663
616664```
617665truenull
0 commit comments