题目:程序运行期发生 ClassNotFoundException 可能是什么原因?
难度:low
标签:practice/debug, java/classloading
评分:⭐⭐⭐☆☆(3/5)
运行期间发生 class not found 一般是因为包的异常,引入包的异常,存在包冲突,某些包应该被其他引入了,但是没有被引入。
另外就是反射,反射使用获取了一个不存在的包,也可能会是 class not find。
再有就是一些动态加载的东西,这时候也可能会产生 class not find。
核心原因还是找不到,找不到对应的包,对应的类。
找不到的原因,可能是包冲突导致相互之间的冲突无法正常使用,可能是使用反射读取到错误的类名,都是有可能。根据具体的报警位置,然后去排查对应的问题。如果是包冲突,就对进,对行,进行相应调整。排除依赖或者引入新依赖,引入共享依赖。
明显是类名错误反射引起的,那么就对应的检查是何处传来了错误的类。对应的进行处理。
优点:
不足:
补充:
META-INF/services)配置类名拼写错误jcmd <pid> VM.classloader_stats / VM.classloader_dump、arthas sc -d <class>、Maven dependency:tree、-verbose:class 打印类加载日志核心考点定位:考察对 JVM 类加载机制的深度理解——不只是"找不到类",而是"什么时候、在哪一层找不到"。
知识点拆解:
Class.forName("xxx") 找不到provided 作用域依赖漏打、shade/uber-jar 过滤规则错误、多 ClassLoader 隔离(Tomcat/OSGi)、SPI 配置错、JDK 版本升级(javax. → jakarta.)jcmd VM.classloader_dump、arthas sc -d、dependency:tree、-verbose:class、java -Xbootclasspath 检查扩展考察方向:
loadClass 三阶段:findLoadedClass → findBootstrapClass → findClass)、双亲委派破坏场景(SPI、热部署)UnsatisfiedLinkError(native 库缺失)、ExceptionInInitializerError(静态块失败)的区分延伸递进面试题:
jcmd <pid> VM.classloader_dump <id> 看每个 CL 的 URL;arthas sc -d <class> 直接查类的 ClassLoader 和 jar 路径;异常堆栈里找 ClassLoader 类型【一句话结论】
面试官您好,"运行期"这个关键词很重要——不是启动就报错,说明类路径没变,问题大概率来自"延迟加载触发"或"多 ClassLoader 隔离",我会先确认异常类型(CNFE 还是 NCDFE),再按 ClassLoader 层级排查。
【三点展开】
第一,先区分异常类型:ClassNotFoundException 是首次加载找不到 .class;NoClassDefFoundError 是曾经加载过但依赖缺失或静态初始化失败。后者更隐蔽,往往静态块里调用的类被 shade 过滤掉才会踩到。
第二,看调用栈定位触发路径:是反射 Class.forName 触发,还是 CGLIB 动态代理生成代理类失败,还是延迟执行的代码路径首次走。反射路径查传入的类名字符串对不对;动态代理查父类加载器和父类可见性。
第三,用 arthas sc -d <className> 看类的 ClassLoader 和 jar 路径,用 jcmd <pid> VM.classloader_dump 看每个 CL 的 URL 列表,确认类在哪个 ClassLoader 范围内。常见根因:Maven provided 依赖漏打、shade 过滤规则错误、Spring Boot 与 Tomcat 的 ClassLoader 差异、SPI 配置拼写错误。
【一句边界】
当然,如果是 JDK 9+ 模块系统,跨模块访问的类还会被 IllegalAccessError 拦截,那是另一个坑——运行期突然 CNFE 也可能只是模块名拼错触发的假象。