Class.newInstance() 在 Java 9+ 已废弃,因绕过访问检查、不支持带参构造器,且 JDK 14 后部分环境禁用;应改用 Constructor.newInstance() 并缓存 Constructor 实例。

用 Class.newInstance() 创建对象为什么报错?
Java 9+ 已废弃 Class.newInstance(),调用会抛 IllegalAccessException 或直接失败——它绕过构造器访问检查,且无法处理带参构造器。真实项目中几乎不该用它。
- 仅适用于无参、public 构造器,且类必须已初始化
- JDK 9 起被标记为 deprecated,JDK 14 后部分运行时彻底禁用
- 替代方案统一走
Constructor.newInstance(...)
如何安全调用带参构造器?
必须先获取 Constructor 对象,显式设置可访问性,并传入匹配类型和数量的参数。
- 用
clazz.getConstructor(String.class, int.class)获取 public 构造器;若为 private,改用getDeclaredConstructor(...) - 调用前必须执行
constructor.setAccessible(true)(否则私有构造器抛IllegalAccessException) - 参数类型必须严格匹配:传
int却用Integer.class查找会抛NoSuchMethodException
Constructorctor = User.class.getDeclaredConstructor(String.class, int.class); ctor.setAccessible(true); User user = ctor.newInstance("Alice", 25);
反射创建对象比 new 慢多少?有没有缓存必要?
单次调用慢 3–5 倍,主要耗在安全检查、类型校验和方法解析;但真正影响性能的是反复查找 Constructor ——每次 getDeclaredConstructor 都触发内部遍历。
- 应缓存
Constructor实例(而非Class),尤其在高频场景如 ORM 实体映射、JSON 反序列化 - 注意线程安全:
setAccessible(true)是线程安全的,但缓存结构本身需同步或用ConcurrentHashMap - 避免缓存未校验的
Constructor:不同类加载器下相同类名可能对应不同Class对象
Spring/MyBatis 里反射创建对象,为啥没见 setAccessible?
它们确实调用了 setAccessible(true),只是封装在工具类里(如 Spring 的 ReflectionUtils),默认开启「暴力反射」模式。
立即学习“Java免费学习笔记(深入)”;
- Spring 5.2+ 默认对所有非 public 成员启用
setAccessible,除非显式关闭ReflectionUtils.setAccessible(true) - MyBatis 使用
ObjectFactory接口,默认实现DefaultObjectFactory内部就做了constructor.setAccessible(true) - 如果你手动写工具类,别漏掉这行——否则 private 构造器在模块化(JPMS)环境下必然失败
Constructor;也不是「设了 setAccessible 就一劳永逸」,得确认目标类没被模块系统限制(如未在 module-info.java 中开放包)。










