Unsafe.allocateInstance不分配新内存,而是绕过构造器在类已有内存布局上“伪造”实例,字段全为默认值,不触发任何初始化逻辑,包括final字段赋值和实例块;仅适用于已加载且JVM支持的类。

Unsafe.allocateInstance 并不分配新内存,而是绕过构造器、在已有类的内存布局基础上“伪造”一个实例——它复用类的静态内存结构,但不会调用任何构造方法,也不会触发字段初始化(包括 final 字段的赋值、实例初始化块等)。
核心限制:对象处于未完全初始化状态
该方法仅适用于**已加载且具有默认构造能力的类**(即存在无参构造器,或为数组/基本类型包装类等 JVM 特殊支持类型),但即使有构造器,allocateInstance 也跳过所有构造逻辑。例如:
- 普通类中
private final String name = "default";不会被执行,字段保持默认值(null、0、false); - 构造器里的资源申请(如打开文件、注册监听)完全不会发生;
- 如果类依赖构造器做必要校验(如参数检查、状态设置),直接使用该实例可能导致
NullPointerException或逻辑错误。
获取 Unsafe 实例(JDK 9+ 需反射绕过模块限制)
由于 Unsafe 是受限 API,标准方式已被封禁,需通过反射获取:
- JDK 8 可直接调用
Unsafe.getUnsafe()(仅限 boot classpath 加载的类); - JDK 9 及以后必须用反射访问私有构造器:
Field f = Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); Unsafe u = (Unsafe) f.get(null);; - 部分 JDK(如 OpenJDK 17+)可能进一步限制反射访问,需添加 JVM 参数如
--add-opens=java.base/jdk.internal.misc=ALL-UNNAMED。
典型适用场景与替代建议
真正需要 allocateInstance 的情况极少,常见于:
立即学习“Java免费学习笔记(深入)”;
- 序列化框架(如 Kryo、FST)反序列化时跳过构造、直接填充字段;
- 高性能对象池中避免重复构造开销(但需确保后续手动初始化字段);
- 测试中构造特殊状态的对象(如
final字段尚未赋值的实例)。
日常开发中,更安全的做法是:优先使用常规 new + 构造器;若需绕过构造逻辑,考虑 Objenesis 库(封装了多种底层机制,兼容性更好),而非直接操作 Unsafe。
简单示例(仅演示,勿在生产环境直接使用)
假设有一个无逻辑的 POJO:
public class Person {
private final String name;
private int age;
public Person() { this.name = "unknown"; } // 构造器设了 name
}
用 allocateInstance 创建后,name 为 null,不是 "unknown" —— 因为构造器根本没运行。


















