486. Java 反射 - 构造器调用模式
在反射中,构造器的调用主要有两种方式:
Class.newInstance()(已弃用 ❌)Constructor.newInstance()(推荐 ✅)
1. 为什么 Class.newInstance() 被弃用?
在 Java SE 9 之后,Class.newInstance() 就不推荐再用了,原因有三点:
- 🚫 只能调用无参构造器 无法调用带参数的构造器。
- 🚫 异常处理不合理 构造器抛出的任何异常(受检 / 非受检)都会被原样抛出,绕过了编译期检查。
- 🚫 访问限制过于严格 只能调用 public 无参构造器,无法调用私有构造器。
👉 因此,我们现在应该统一使用 Constructor.newInstance()。
2. 正确的调用方式:Constructor.newInstance()
调用模式:
Constructor<T> constructor = clazz.getConstructor(参数类型...);
T instance = constructor.newInstance(参数值...);
好处:
- ✅ 可以调用任意构造器(带参 / 无参)
- ✅ 异常会被包装在
InvocationTargetException里,避免绕过编译器检查 - ✅ 可以配合
setAccessible(true)调用私有构造器
3. 示例:创建 String 实例
Class<String> stringClass = String.class;
// 获取无参构造器
String emptyString = stringClass.getConstructor().newInstance();
System.out.println("Empty? " + emptyString.isEmpty());
输出:
Empty? true
📌 注意:
- 如果类没有无参构造器,会抛出
NoSuchMethodException - 如果类是抽象类 / 接口,会抛出
InstantiationException - 如果构造器不可见(如 private),会抛出
IllegalAccessException
4. 示例:调用 Record 构造器
Java 14 引入了 record,它们自带一个 canonical constructor(所有字段作为参数的构造器)。
public record Point(int x, int y) {
public Point() { // 自定义无参构造器
this(0, 0);
}
}
4.1 调用无参构造器
Class<Point> c = Point.class;
Constructor<Point> constructor = c.getConstructor();
Point p = constructor.newInstance();
System.out.println("p = " + p);
输出:
p = Point[x=0, y=0]
4.2 调用 canonical 构造器
Class<Point> c = Point.class;
Constructor<Point> constructor = c.getConstructor(int.class, int.class);
Point p = constructor.newInstance(1, 1);
System.out.println("p = " + p);
输出:
p = Point[x=1, y=1]
📌 说明:
- 即使代码里没写,编译器也会自动生成
Point(int x, int y)构造器。 - 这就是 canonical constructor。
5. 总结
- ✅ 以后统一用
Constructor.newInstance(),不要用Class.newInstance() - ✅
newInstance()总是可能抛出以下异常:InvocationTargetException(包装构造器抛出的异常)InstantiationException(抽象类 / 接口无法实例化)IllegalAccessException(构造器不可见时)
- ✅ 结合
setAccessible(true)可以突破访问限制(但模块化下可能失败)