Class.forName()通过全限定名加载类并触发初始化,用于动态获取Class对象、注册JDBC驱动等;其核心区别在于会执行静态代码块,而ClassLoader.loadClass()不触发初始化,更轻量安全。

直接通过代码判断JDK是否支持某特性,核心思路是:**避免硬编码版本号比较,优先利用Java自身的运行时能力探测(如类是否存在、方法是否可调用、接口是否实现),辅以版本号检查作为兜底**。
检查类或接口是否存在
很多新特性会引入新类或接口(如 var 对应 java.lang.Class 无新增,但 Record 类型依赖 java.lang.Record 类)。可通过 Class.forName() 判断:
- 若抛出
ClassNotFoundException,说明该类在当前JDK中不存在 → 特性不支持 - 成功加载则大概率支持(需注意部分类虽存在但功能受限,如早期
HttpClient在 JDK 9+ 存在但直到 JDK 11 才正式稳定)
示例:判断是否支持 java.net.http.HttpClient(JDK 11 引入):
Class.forName("java.net.http.HttpClient");
// 支持
} catch (ClassNotFoundException e) {
// 不支持
}
检查方法是否可用(含反射调用)
某些特性表现为已有类新增方法(如 String.isBlank() 是 JDK 11 新增)。可用反射检测:
- 获取目标类的
Method对象,成功则说明方法存在 - 注意:需处理
NoSuchMethodException和SecurityException - 对 public static 方法更稳妥;实例方法需先有实例,可能触发初始化副作用
示例:判断 String.isEmpty() 早已存在,但 isBlank() 是 JDK 11+:
String.class.getMethod("isBlank");
// 支持
} catch (NoSuchMethodException e) {
// 不支持
}
利用标准API进行能力探测(推荐)
部分特性提供标准的运行时检测方式,比手动反射更可靠:
-
System.getProperty("java.version")或Runtime.version()(JDK 9+)获取版本信息,再解析比较。注意语义化版本(如 "17.0.1")需谨慎解析,建议用Runtime.version().feature()获取主版本号 - JDK 9+ 推荐用
Runtime.version().compareTo(Version.parse("17")) >= 0判断是否 ≥ JDK 17 - 对模块化特性(如
java.xml.bind在 JDK 9 被标记为 deprecated,JDK 11 移除),可用ModuleLayer.boot().findModule("java.xml.bind")检查模块是否存在
注意边界情况和陷阱
仅靠版本号或类存在性可能误判:
- 某些特性分阶段引入(如
Switch Expressions在 JDK 12 作为预览特性,默认关闭;JDK 14 再次预览;JDK 14+ 需显式启用--enable-preview;JDK 15 正式发布)。此时仅看类/方法存在不能代表“默认可用” - 预览特性需配合 JVM 参数,代码中无法安全启用,只能提示用户配置
- 部分 API 存在但行为不同(如
CompletableFuture.delayedExecutor在 JDK 9+ 存在,但线程池策略细节有演进),探测存在性 ≠ 行为一致
真正健壮的判断,往往需要结合“类存在 + 方法可用 + 运行时行为验证(如小范围测试调用)”,尤其对关键路径特性。

















