ClassNotFoundException 是反射加载时因类在 classpath 中不存在而抛出的检查异常,必须处理;NoClassDefFoundError 是隐式引用时因编译存在、运行缺失类定义而抛出的致命错误,属 Error 不可捕获。

ClassNotFoundException 是反射加载失败时抛出的检查异常
它只在你主动调用 Class.forName()、ClassLoader.loadClass() 或 ClassLoader.findSystemClass() 时发生,且类在 classpath 中压根不存在。JVM 编译期完全不管这事,运行到这行才去查——查不到就抛 ClassNotFoundException,而且必须 try-catch 或声明抛出,否则编译不通过。
- 典型场景:JDBC 加载驱动时写错类名,比如
Class.forName("com.mysql.cj.jdbc.Driver")写成"com.mysql.jdbc.Driver"(旧版),或没把 mysql-connector-java.jar 放进 classpath - 错误堆栈里一定有
java.lang.ClassNotFoundException开头,且紧跟着at java.lang.Class.forName0(Native Method) - 不是“找不到 jar”,而是“jar 里没这个类”或“类名拼错了”——哪怕 jar 在 classpath 里,类名对不上照样报
NoClassDefFoundError 是隐式引用失败时抛出的致命错误
它意味着这个类**编译时存在、运行时却没了定义**。JVM 在 new 实例、访问静态字段、调用静态方法等隐式触发类加载的时刻,突然发现“咦?我明明编译过你,怎么现在找不到了?”——于是直接抛 NoClassDefFoundError,属于 Error,不能也不该 try-catch。
- 常见原因:打包漏文件(如 Maven 多模块中 A 模块依赖 B 模块的类,但 assembly 插件没把 B 的 jar 打进去)、运行时 classpath 被覆盖、或某个类因静态块抛异常导致初始化失败(后续再引用该类就会触发此 Error)
- 注意看错误信息:是
java.lang.NoClassDefFoundError: xxx/SomeClass,不是 ClassNotFoundException;堆栈里往往没有你写的代码行,而是在某次 new 或 static 访问处中断 - 特别容易误判为“jar 没加”,其实 jar 可能加了,但里面没包含你要的那个 class —— 比如用了 shade 插件但没配置
minimizeJar,结果把依赖类裁掉了
打包阶段最容易踩的坑:Maven 依赖传递与 scope 混淆
Maven 默认 compile scope 会参与编译和运行,但 test 和 provided scope 不会打进最终包。如果你在代码里 new 了一个只在 test scope 下才有的类(比如某些 mock 工具类),编译能过,运行必报 NoClassDefFoundError。
- 检查方式:运行
mvn dependency:tree -Dincludes=xxx:artifact-id,确认目标类所属 jar 确实出现在 runtime classpath 中 - IDEA/Eclipse 里右键项目 → “Open Module Settings” → 查看 “Libraries” 和 “Artifacts” 是否真包含了那个 jar;别只信 pom.xml 写了就完事
- 使用 Spring Boot 时,
spring-boot-maven-plugin的 repackage 目标默认打 fat jar,但如果自定义了layout=ZIP或用了thin jar模式,类路径逻辑完全不同,得额外验证启动时的-cp
运行时 classpath 覆盖比你想象中更隐蔽
Java 启动命令里的 -cp 或 -classpath 会完全覆盖 JAVA_CLASSPATH 环境变量,而很多容器(Tomcat、WebLogic)又自带启动脚本,它们内部拼接 classpath 的顺序可能把你本地加的 jar 给挤掉。
立即学习“Java免费学习笔记(深入)”;
- 验证手段:在 main 方法开头加一行
System.out.println(System.getProperty("java.class.path"));,看实际生效的路径里有没有你指望的那个 jar - Tomcat 下尤其注意
lib目录和WEB-INF/lib的优先级;两个地方都有同名 jar 且版本不同,可能引发NoClassDefFoundError(因为类加载器委托链先加载了旧版,但新版类定义缺失) - Linux 下注意路径分隔符是
:,Windows 是;;写错一个符号,整个 classpath 就废了,JVM 不报错,只是默默忽略无效段










