ClassNotFoundException与NoClassDefFoundError

时间:2015-02-04 13:38:24

标签: java exception noclassdeffounderror classnotfoundexception

我已经完成了这个帖子What causes and what are the differences between NoClassDefFoundError and ClassNotFoundException? 这是一个在线程中具有max ups的ans之一: NoClassDefFoundError :"因此,似乎在成功编译源时出现NoClassDefFoundError ,但在运行时,找不到所需的类文件。这可能是在分发或生成JAR文件时可能发生的事情,其中​​并未包含所有必需的类文件。"

ClassNotFoundException :对于ClassNotFoundException,它似乎源于尝试在运行时对类进行反射调用,但程序试图调用的类不存在。

我做了一个小实验。我创建了一个主类 A类,并试图从中调用其他类 B ,编译成功。

然后我删除了在A类中调用的B类。 我得到了 java.lang.ClassNotFoundException 但是根据步骤中的答案,我应该得到NoClassDefFoundError(源代码已成功编译,但未找到运行时类文件) 任何人都可以解释我在线程中对ans的解释中缺少什么吗?

package com.random;

public class A {

    public static void main(String[] args) {
        B b= new B();

    }

}

 package com.random;

public class B {



}

8 个答案:

答案 0 :(得分:13)

<强> NoClassDefFoundError的

  

如果Java虚拟机或ClassLoader实例尝试,则抛出该异常   加载类的定义(作为普通方法调用的一部分或   作为使用新表达式创建新实例的一部分)和否   可以找到班级的定义。

     

当前正在执行的搜索类定义存在   编译了类,但无法再找到定义。


<强> ClassNotFoundException的

  

当应用程序尝试通过其字符串加载类时抛出   name using:类Class中的forName方法。 findSystemClass   ClassLoader类中的方法。类中的loadClass方法   类加载器。


您必须了解JVM无法实现您删除的class的定义无法找到,因为class本身无法自动找到抛出ClassNotFoundException

此异常发生在runtime,因此无论是否先编译都没关系,您删除了该文件,因此无法找到它并抛出exception

请注意,NoClassDefFoundError实际上并不是例外情况,Error来自LinkageErrorClassNotFoundException直接来自java.lang.Exception

要恢复,全局NoClassDefFoundError只是表示JVM尝试访问runtime根据compiled代码存在的内容,但实际上并不存在(或不在类路径中)。


重现ClassNotFoundException的示例

public class ClassNotFoundExceptionExample {

    private static final String CLASS_TO_LOAD = "main.java.Utils";

    public static void main(String[] args) {
        try {
            Class loadedClass = Class.forName(CLASS_TO_LOAD);
            System.out.println("Class " + loadedClass + " found successfully!");
        }
        catch (ClassNotFoundException ex) {
            System.err.println("A ClassNotFoundException was caught: " + ex.getMessage());
            ex.printStackTrace();
        }
    }
}

重现NoClassDefFoundError的示例

创建一个简单的类Test

public class Test {
        public Test() {
                System.out.println("A new instance of the Test class was created!");
        }
}

班级NoClassDefFoundErrorExample

public class NoClassDefFoundErrorExample {
        private static Test test = new Test();

        public static void main(String[] args) {
                System.out.println("The definition of Test was found!");
        }
}

现在创建一个执行.jar方法的可执行文件main。您可以在Manifest.txt

中的.jar文件中指定它
Main-Class: NoClassDefFoundErrorExample

现在运行以下命令

javac Test.java
javac NoClassDefFoundErrorExample.java
jar cfm NoClassDefFoundErrorExample.jar Manifest.txt NoClassDefFoundErrorExample.class
java -jar NoClassDefFoundErrorExample.jar

注意NoClassDefFoundError

Exception in thread "main" java.lang.NoClassDefFoundError: TestClass
    at NoClassDefFoundErrorExample.(NoClassDefFoundErrorExample.java:2)
Caused by: java.lang.ClassNotFoundException: TestClass
    at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 1 more

答案 1 :(得分:10)

嗯... ClassNotFoundException发生在运行时试图找到某个String命名的类时,例如Class.forName(java.lang.String)方法取一个字符串参数并尝试用这个来查找类名称。在这种情况下,类名是一个sting,只能在运行时检查。这里的例外清楚地说......没有找到这个“阶级”。所以......它可能有两个原因:

原因1.类名不是有效的java类(例如“java.bang.kiting”)。

// Example    
Class cdef = Class.forName( "java.bang.kiting" );

原因2.类名是一个有效的类...但不知何故它没有与jar打包或在类路径中没有解析。因此,就运行时所知......它可能是一个错误的类名...类似于情况1。

// Example    
Class cdef =Class.forName( "apache.some.SomeLegitClass" );

对于使用实际类引用的情况,NoClassDefFoundError

// example
import apache.some.SomeLegitClass
SomeLegitClass i = (SomeLegitClass) instanceOfSomeLegitClass;

所以基本上一切都是正确的,但不知何故,这个类没有与jar打包(或者更一般地说 - 在类路径中没有解决)。在这种情况下,我们得到NoClassDefFoundError

这里运行时知道该类是有效的,因为它已成功编译...但它找不到“类定义”。

答案 2 :(得分:2)

当您使用库(例如,Guava,Gson,CommonsIO)时,通常会调用

NoClassDefFoundError。您将库放在项目的类路径中,但是您没有将它们一起导出,当应用程序运行时,您将获得NoClassDefFoundError

如何获得NoClassDefFoundError
使用此类创建一个新项目。

public class A
{
    public void do()
    {
        System.out.println("Do!");
    }
}  

将其导出为.jar文件。

现在创建另一个项目。将导出的jar文件添加到classpath。

import ???.A;
public class Main
{
    public static void main(String[] args)
    {
        A a = new A();
        a.do();//NoClassDefFoundError thrown at here.
    }
} 

导出项目,确保不包含jar文件(使用类A)。运行新导出的jar文件,您将看到该错误!

答案 3 :(得分:1)

1) ClassNotFoundException

  1. 当我们尝试使用Class.forName()ClassLoader.loadClass()ClassLoader.findSystemClass()方法在运行时加载一个类时,会发生这种情况,并且可以找到所需的类路径中的类。
  2. 在这种情况下,我们应检查class path并在类路径中添加该类(如果缺少)。
  3. 这是已检查的异常,它源自 java.lang.Exception 类。
  4. 这是显式加载。
  5. 2) NoClassDefFoundError

    1. compile time期间出现该课程时出现这种情况,并且由于某些原因在run time期间无法使用。这意味着加载的类在present中为classpath,但此类所需的其中一个依赖classe(s)要么已删除,要么失败由编译器加载。

    2. 在这种情况下,我们只需要查看classes which are dependent on this class

    3. 这是错误,源自 java.lang.LinkageError
    4. 这是隐式加载。

答案 4 :(得分:1)

如前面的答案中所述,当编译时出现类时,NoClassDefFoundError会出现,并且由于某些原因在运行时不可用。

我想添加另一个场景,这也可能导致NoClassDefFoundError。

当您尝试加载由于某些异常导致无法加载的类时,表示静态初始化块失败,系统将抛出ExceptionInInitializerError。如果再次尝试加载同一个类(以前无法加载),系统将抛出NoClassDefFoundError

让我们用样本

来探索它

<强> ClassWithStaticBlock.java

public class ClassWithStaticBlock {

    static {
       int total = 1/0;
    }
}

<强> Main.java

public class Main {

public static void main(String[] args) {
    ClassWithStaticBlock cs;
    try {
       cs = new ClassWithStaticBlock();
    }catch(Throwable e){
        e.printStackTrace();
    }
  }
}

<强>结果:

java.lang.ExceptionInInitializerError
    at Main.main(Main.java:6)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: java.lang.ArithmeticException: / by zero
    at ClassWithStaticBlock.<clinit>(ClassWithStaticBlock.java:7)
    ... 6 more

让我们修改 Main.java

public class Main {

    public static void main(String[] args) {
        ClassWithStaticBlock cs;
        try {
           cs = new ClassWithStaticBlock();
        }catch(Throwable e){
            e.printStackTrace();
        }
        cs = new ClassWithStaticBlock(); //try to use ClassWithStaticBlock again
    }
}

<强>结果:

java.lang.ExceptionInInitializerError
    at Main.main(Main.java:6)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: java.lang.ArithmeticException: / by zero
    at ClassWithStaticBlock.<clinit>(ClassWithStaticBlock.java:7)
    ... 6 more
Exception in thread "Main Thread" java.lang.NoClassDefFoundError: ClassWithStaticBlock
    at Main.main(Main.java:10)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

当我们再次尝试使用ClassWithStaticBlock时(之前未能初始化),System正在抛出NoClassDefFoundError。

Why am I getting a NoClassDefFoundError in Java?

找到样本

答案 5 :(得分:0)

在运行时未找到特定类时会发生ClassNotFoundException和NoClassDefFoundError。但是,它们出现在不同的场景中。

ClassNotFoundException是当您尝试使用Class.forName()或loadClass()方法在运行时加载类时发生的异常,并且在类路径中找不到提到的类。

public class MainClass
{
    public static void main(String[] args)
    {
        try
        {
            Class.forName("oracle.jdbc.driver.OracleDriver");
        }catch (ClassNotFoundException e)
        {
            e.printStackTrace();
        }
    }
}



java.lang.ClassNotFoundException: oracle.jdbc.driver.OracleDriver
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
at pack1.MainClass.main(MainClass.java:17)

NoClassDefFoundError是在编译时出现特定类但在运行时丢失时发生的错误。

class A
{
  // some code
}
public class B
{
    public static void main(String[] args)
    {
        A a = new A();
    }
}

编译上述程序时,将生成两个.class文件。一个是A.class,另一个是B.class。如果删除A.class文件并运行B.class文件,Java Runtime System将抛出NoClassDefFoundError,如下所示:

Exception in thread "main" java.lang.NoClassDefFoundError: A
at MainClass.main(MainClass.java:10)
Caused by: java.lang.ClassNotFoundException: A
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)

答案 6 :(得分:0)

Everything About ClassNotFoundException Vs NoClassDefFoundError文章非常清楚地解释了ClassNotFoundException与NoClassDefFoundError之间的区别,并根据它进行了解释。

ClassNotFoundException Vs NoClassDefFoundError -- Programming Mitra

ClassNotFoundException的

当我们告诉JVM使用Class.forName()或ClassLoader.findSystemClass()或ClassLoader.loadClass()方法通过其字符串名称加载类时发生的已检查异常,并且在类路径中找不到提到的类。

大多数情况下,当您尝试运行应用程序而不使用所需的JAR文件更新类路径时,会发生此异常。例如,在执行JDBC代码连接到数据库时,可能已经看到了这个异常,即MySQL,但是你的类路径没有jar。

public class Test {
    public static void main(String[] args) throws Exception {

        // Provide any class name to Class.forName() which does not exist
        // Or compile Test.java and then manually delete Person.class file so Person class will become unavailable
        // Run the program using java Test

        Class clazz = Class.forName("Person");
        Person person = (Person) clazz.newInstance();
        person.saySomething();
    }
}

class Person {
    void saySomething() {
        System.out.println("Hello");
    }
}

NoClassDefFoundError的

java.lang.Error的子类型和Error类表示应用程序实际上不应该发生的异常行为,但应用程序开发人员不应该尝试捕获它,它只适用于JVM。

当JVM尝试加载作为代码执行一部分的特定类(作为普通方法调用的一部分或作为使用new关键字创建实例的一部分)并且类路径中不存在该类时,会发生NoClassDefFoundError但是在编译时出现,因为为了执行你的程序,你需要编译它,如果你正在尝试使用一个不存在的类,编译器将引发编译错误。

public class Test {
    public static void main(String[] args) throws Exception {

        // Do javac on Test.java, 
        // Program will compile successfully because Empoyee class exits
        // Manually delete Employee.class file
        // Run the program using java Test
        Employee emp = new Employee();
        emp.saySomething();

    }
}

class Employee {
    void saySomething() {
        System.out.println("Hello");
    }
}

答案 7 :(得分:-1)

这个帖子中的其他答案是正确的,我只想添加一些我花费数小时试图找出的东西。即使

Class.forName("apache.some.SomeLegitClass")

作品,

Class.forName("apache.some.somelegitclass")

将导致NoClassDefFoundError。 Class.forName()区分大小写。如果类名拼写错误,或者只是包含不正确的大小写,则会导致不同的异常。