Java中Unsafe.objectFieldOffset获取字段相对于对象头的字节偏移量,需通过反射获取非静态、可访问的Field实例,返回值用于Unsafe直接内存读写,但属非标准API且受JVM参数和版本限制。

Java 中通过 Unsafe.objectFieldOffset 获取字段的内存相对偏移量,本质是借助 JVM 内部机制获取某个字段在对象内存布局中的起始位置(相对于对象头的字节偏移)。这个值不是绝对地址,而是用于后续通过 Unsafe 直接读写字段的依据。
前提:获取对应 Field 对象
必须先用反射拿到目标字段的 java.lang.reflect.Field 实例,且该字段不能是静态字段(静态字段没有对象内偏移,objectFieldOffset 不适用)。
- 字段需是 public、protected、default 或通过
setAccessible(true)突破访问限制 - 不能是 final 字段(JDK 9+ 对 final 字段的偏移获取虽不报错,但后续写入会失败或触发异常)
- 示例:
Field f = MyClass.class.getDeclaredField("value"); f.setAccessible(true);
调用 objectFieldOffset 获取偏移量
传入上一步得到的 Field 对象,返回 long 类型的偏移值:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
long offset = Unsafe.getUnsafe().objectFieldOffset(f);- 返回值是相对于对象起始地址(即对象头起始处)的字节偏移,例如可能为 12、16、24 等,取决于 JVM 的对象布局(如是否开启压缩指针、字段顺序、对齐要求等)
- 注意:不同 JVM 参数(如
-XX:+UseCompressedOops)会影响实际偏移,同一字段在不同环境可能值不同
典型使用场景:绕过正常访问逻辑
获取偏移后,常配合 Unsafe.getObject / Unsafe.putInt 等方法直接操作内存:
立即学习“Java免费学习笔记(深入)”;
MyClass obj = new MyClass();int value = Unsafe.getUnsafe().getInt(obj, offset); // 读取 int 字段Unsafe.getUnsafe().putInt(obj, offset, 42); // 写入新值- 这种操作跳过了访问控制、final 检查和 volatile 语义,仅适用于高性能底层库(如
java.util.concurrent中的部分实现)
注意事项与限制
该能力属于 JVM 内部 API,非公开标准,使用需谨慎:
- JDK 9 引入模块系统后,
Unsafe默认不可达,需添加 JVM 参数如--add-opens java.base/jdk.internal.misc=ALL-UNNAMED - 某些 JDK 版本(如 JDK 17+)已将部分
Unsafe方法标记为 deprecated,未来可能移除或替换为VarHandle - 字段偏移在类加载后固定,但若类被重新定义(如热替换),偏移可能变化,不应缓存跨生命周期使用

















