发布于2026-07-15 阅读(0)
扫一扫,手机访问
Ja va 中通过 Unsafe 动态读写对象的 private 字段,这事儿说白了就是绕过 JVM 的访问控制,直接对着对象在堆内存里的偏移地址下黑手。属于底层骚操作,只在极少数场景——比如高性能框架、序列化库、JVM 工具开发中才会用到。**业务代码千万别碰**,而且从 JDK 9 开始已经被严格限制,到了 JDK 17+ 默认就不可用了(得额外加 JVM 参数并声明模块权限才能玩)。
Ja va中通过Unsafe动态读写private字段本质是绕过JVM访问控制、直接操作内存偏移,仅限高性能框架等特定场景,不推荐业务使用;JDK9+强限制,需模块权限或JVM参数;推荐改用VarHandle等官方替代方案。

Unsafe 的 getUnsafe() 方法已经不对外公开了——只有 Bootstrap ClassLoader 加载的类才能直接调。常见的兼容手法有这么几种:
--illegal-access=permit 或 --add-opens)jdk.internal.misc.Unsafe 并配合模块导出(启动参数:--add-modules jdk.unsupported --add-opens ja va.base/jdk.internal.misc=ALL-UNNAMED)VarHandle(JDK 9 引入,线程安全、跨平台、JVM 保护妥妥的)Unsafe 不认字段名,只认内存地址偏移。得靠 objectFieldOffset() 拿到目标 private 字段在对象内的字节偏移:
static final 常量会被 JVM 内联,根本没法可靠定位staticFieldOffset(),实例字段用 objectFieldOffset(Field)拿到 Unsafe 实例和字段偏移后,就能用原子或非原子方法直接读写了:
unsafe.getInt(obj, offset)(obj 不能是 null,offset 是字段在该对象中的偏移)unsafe.putInt(obj, offset, newValue)private static 字段,用 getInt(null, offset) / putInt(null, offset, v)getLong、getObject、putObject 等;如果要保证 volatile 语义,用 getAndSetInt 这类原子方法直接操作内存字段,稍不留神就会翻车:
Unsafe 操作还按原地址读写,数据直接错乱(不过对堆内对象,JVM 会保证偏移有效,实际不用手动处理)VarHandle(支持 private 字段、编译器/JVM 优化友好、有明确的内存模型语义),或者 MethodHandles.Lookup(JDK 15+ 支持私有字段查找)
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8