NoClassDefFoundError原因解析

介绍

首先来说明一下NoClassDefFoundError和ClassNotFoundException的区别。

NoClassDefFoundError表明一个类在编译时是能找到的,但是在运行时找不到了。

ClassNotFoundException表示在运行时尝试加载类时找不到这个类。它不会在编译时去查找。

可能的原因

  1. 类不在类路径上(Classpath)

    比如缺少了某些JAR包,或者Jar包没有被放在类路径上,或者JAR包改名字了因此找不到。

  2. 你可能通过jar命令运行的程序,并且类不在manifest文件中ClassPath属性定义的路径上

    这个可以通过System.getProperty("java.classpath")来打印类路径查看是否有你的类所在的路径。

  3. 有启动脚本覆盖了Classpath环境变量

    通过-classpath选项来指定类路径,如果指定类路径成功运行了,那么就是Classpath被覆盖了。

  4. 因为NoClassDefFoundErrorjava.lang.LinkageError的子类,因此也可能是因为如本地库依赖找不到

  5. 检查日志文件中是否有ExceptionInitializerError错误,因为如果类静态初始化失败也可能会导致抛出NoClassDefFoundError

    因为JVM初始化一个类时是线程安全的,所以如果你利用类的静态代码块来实现线程安全,但是在静态代码块中抛出了异常,那么这个类可能会抛出NoClassDefFoundError。同时如果你查看日志文件的话,应该也有ExceptionInitializerError,因为正式由于ExceptionInitializerError触发了java.lang.NoClassDefFoundError:Could not initialize class

    如下面的代码会因为静态代码块失败抛出NoClassDefFoundError:

    /**
     * Java program to demonstrate how failure of static initialization subsequently cause
     * java.lang.NoClassDefFoundError in Java.
     * @author Javin Paul
     */
    public class NoClassDefFoundErrorDueToStaticInitFailure {
    
       public static void main(String args[]){
           
            List<User> users = new ArrayList<User>(2);
           
           for(int i=0; i<2; i++){
               try{
                users.add(new User(String.valueOf(i))); //will throw NoClassDefFoundError
               }catch(Throwable t){
                    t.printStackTrace();
               }
           }        
       }
    }
    
    class User{
       private static String USER_ID = getUserId();
       
       public User(String id){
           this.USER_ID = id;
       }
       private static String getUserId() {
           throw new RuntimeException("UserId Not found");
       }    
    }
    
    Output
    java.lang.ExceptionInInitializerError
        at testing.NoClassDefFoundErrorDueToStaticInitFailure.main(NoClassDefFoundErrorDueToStaticInitFailure.java:23)
    Caused by: java.lang.RuntimeException: UserId Not found
        at testing.User.getUserId(NoClassDefFoundErrorDueToStaticInitFailure.java:41)
        at testing.User.<clinit>(NoClassDefFoundErrorDueToStaticInitFailure.java:35)
        ... 1 more
    java.lang.NoClassDefFoundError: Could not initialize class testing.User
        at testing.NoClassDefFoundErrorDueToStaticInitFailure.main(NoClassDefFoundErrorDueToStaticInitFailure.java:23)
    
  6. 如果是在J2EE环境中,则也可能是由于类在多个类加载器中的可见性问题。

    比如说有一个类User同时出现类WAR文件和EJB-JAR文件中,假设有一个子类加载器ChildClassLoader同时加载WAR包中和EJB-JAR包中的User类,那么这时候当EJB-JAR中的代码引用类User时,EJB-JAR包的类加载器ClassLoader找不到类User,因为它是被子类加载器ChildClassLoader加载了。

    这个例子举的有点模糊,因为什么情况下会是EJB-JAR包的类User由子类加载器加载,而EJB-JAR包中的其他类由类加载器自身而不是子类加载器加载呢?

  7. 如果你是用的是ANT来进行构建jar包,那么要确保在ANT脚本中能拿到正确的classpath值并且追加到manifest.mf文件。

  8. 也可能是因为权限问题从而导致无法读取JAR包。

  9. XML配置书写错误导致根本没有这个类。

  10. 编译过的类应该在它自己的包下却不在那个包下。

  11. 编译后的类文件缺失。比如编译后删除某个类,那么在运行时会直接抛出NoClassDefFoundError,而不会再有ExceptionInitializerError,参考第5条。

参考:https://javarevisited.blogspot.com/2011/06/noclassdeffounderror-exception-in.html#axzz6oZiNtVnD

猜你喜欢

转载自blog.csdn.net/adolph09/article/details/114809165