InstantiationException暴露的是设计缺陷而非运行时异常,需通过编译期预防:确保具体类有public无参构造器、泛型限定为Class<? extends Product>并校验非接口/非抽象、优先用Supplier替代反射、反射场景须预检构造器、避免混用创建策略。

InstantiationException 在工厂模式中通常暴露的是设计缺陷,而非运行时异常本身需要被“健壮处理”——它本质是编译期可预防的错误信号,核心在于避免发生,而非捕获后兜底。
工厂方法返回类型必须与实际构造类兼容
当工厂返回 Class<T> 或通过反射创建实例时,若目标类是抽象类、接口或没有无参构造器,newInstance()(已弃用)或 Constructor.newInstance() 就会抛出 InstantiationException。这不是业务异常,而是契约断裂。
- 确保所有可被工厂创建的具体类都提供 public 无参构造器(除非你显式传入参数并匹配构造签名)
- 工厂方法的泛型边界应限定为
Class<? extends Product>,并在注册/加载阶段校验该 Class 是否是具体类:!clazz.isInterface() && !clazz.isEnum() && !clazz.isSynthetic() && !Modifier.isAbstract(clazz.getModifiers()) - 避免在工厂中直接返回
Class<Object>或未约束的原始Class
用 Supplier 替代反射创建,提前暴露问题
反射绕过了编译检查,把错误推迟到运行时;而 Supplier<T> 是编译安全的工厂封装:
- 注册产品时使用 lambda:
registry.register("pdf", () -> new PdfExporter()); - 调用时直接
supplier.get(),任何构造异常(如 NPE、IllegalArgumentException)都会自然抛出,且类型明确、堆栈清晰 - 既消除了
InstantiationException的可能性,又让依赖注入容器(如 Spring)能统一管理生命周期
反射场景下必须预检 + 明确失败语义
若因框架限制必须用反射(如插件化加载外部 class),则应在初始化阶段完成验证,而不是等到首次创建才崩溃:
立即学习“Java免费学习笔记(深入)”;
- 加载 class 后立即检查:
clazz.getDeclaredConstructor(),捕获NoSuchMethodException并转为初始化失败日志+跳过注册 - 不建议 catch
InstantiationException做重试或默认 fallback——这会掩盖类定义错误,导致后续行为不可预测 - 将校验逻辑封装为
isInstantiable(Class<?>)工具方法,在工厂启动时批量扫描并报告不合规类
避免在工厂中混用多种创建策略
一个工厂同时支持反射、Supplier、Spring BeanName、甚至 Builder 模式,会大幅增加契约理解成本和出错路径:
- 统一选择一种创建机制(推荐 Supplier 或 DI 容器托管)
- 如果必须多源,按优先级分层:先查缓存实例 → 再查 Supplier → 最后才走反射(且反射分支需强制预检)
- 每种策略对应独立的注册 API,例如
registerByClass(...)和registerBySupplier(...),不共用同一方法签名
不复杂但容易忽略:InstantiationException 不是你要 catch 的异常,而是提醒你——工厂契约写错了,或者类没写对。


















