Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/347.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Java中,为什么异常类在';有必要吗?_Java_Exception_Classloader_Noclassdeffounderror - Fatal编程技术网

在Java中,为什么异常类在';有必要吗?

在Java中,为什么异常类在';有必要吗?,java,exception,classloader,noclassdeffounderror,Java,Exception,Classloader,Noclassdeffounderror,我正在开发一个动态加载JAR的应用程序,其中包含它使用的一组类的定义。在我尝试捕获动态加载的JAR中的异常派生类之前,一切都很顺利 下面的代码片段显示了问题(DynamicJarLoader是实际加载JAR的类;TestClass和MyException都在外部JAR中): 当我尝试运行它时,我得到以下结果: Exception in thread "main" java.lang.NoClassDefFoundError: dynamictestjar/MyException Caused b

我正在开发一个动态加载JAR的应用程序,其中包含它使用的一组类的定义。在我尝试捕获动态加载的JAR中的异常派生类之前,一切都很顺利

下面的代码片段显示了问题(
DynamicJarLoader
是实际加载JAR的类;
TestClass
MyException
都在外部JAR中):

当我尝试运行它时,我得到以下结果:

Exception in thread "main" java.lang.NoClassDefFoundError: dynamictestjar/MyException
Caused by: java.lang.ClassNotFoundException: dynamictestjar.MyException
        at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
        at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
Could not find the main class: dynamicjartestapp.Main. Program will exit.
如果我用
catch(异常e)
替换
catch(异常e)
,程序运行正常。这意味着Java能够在JAR已经加载之后找到
TestClass
。因此,JVM似乎需要在程序开始运行时定义所有异常类,而不是在需要它们时(即到达特定的try-catch块时)

为什么会发生这种情况

编辑

我运行了一些额外的测试,这确实很奇怪。这是MyException的完整来源:

package dynamictestjar;
public class MyException extends RuntimeException {
    public void test() {
        System.out.println("abc");
    }
}
此代码运行:

public static void main(String[] args) {
    DynamicJarLoader.loadFile("../DynamicTestJar.jar");
    String foo = new TestClass().testMethod("42");
    new MyException().test(); //prints "abc"
}
这并不是:

  public static void main(String[] args) {
    DynamicJarLoader.loadFile("../DynamicTestJar.jar");
    String foo = new TestClass().testMethod("42");
    new MyException().printStackTrace(); // throws NoClassDefFoundError
  }
我应该指出,每当我从NetBeans运行测试时,一切都按照计划进行。只有当我从Java的眼中强制移除外部Jar并从命令行运行测试应用程序时,这种奇怪才开始

编辑#2

根据答案,我写了这篇文章,我认为这证明了我接受的答案是正确的:

  public static void main(String[] args) {
    DynamicJarLoader.loadFile("../DynamicTestJar.jar");
    String foo = new TestClass().testMethod("42");
    class tempClass {
        public void test() {
            new MyException().printStackTrace();
        }
    }
    new tempClass().test(); // prints the stack trace, as expected
  }
“因此,JVM似乎需要在程序开始运行时定义所有异常类,而不是在需要时”——不,我认为这是不对的

我敢打赌,您的问题是由于您的这些潜在错误造成的,这些错误都与JVM无关:

  • MyException.java文件顶部缺少一个package语句。看起来你想让它成为“PackageDynamicTestJar”,但它不在那里
  • 在MyException.java文件中确实有正确的package语句,但在编译时,没有在名为“dynamictestjar”的文件夹中找到MyException.class文件
  • 当您将代码打包到DynamicTestJar.jar(星球大战迷,您是)中时,您没有获得正确的路径,因为您没有压缩包含文件夹“DynamicTestJar”的目录,因此类加载器看到的路径不正确
  • 这些都不是由于类加载器的神秘性造成的。你需要检查并确保你的工作做得很好

    为什么需要像这样动态加载JAR?你在做什么,仅仅把JAR放在类路径中,然后让类加载器拾取它,是无法完成的

    我希望这只是一个示例,而不是您在Java中的“最佳实践”:

    您至少应该打印堆栈跟踪或使用Log4J记录异常

    更新:

    我应该指出,每当我从NetBeans运行测试时,一切都按照计划进行。只有当我从Java的眼中强制移除外部Jar并从命令行运行测试应用程序时,这种奇怪才开始

    这表明当您从命令行运行时,您硬连接到JAR路径的路径不满足要求


    JVM不能以一种方式使用NetBeans,也不能以另一种方式不使用它。这都是关于理解类路径、类装入器和路径问题的。当您对自己的异常进行分类时,它会起作用。

    MyException是您动态加载的JAR中的异常类吗

    请注意,您是静态地使用MyException类,正如您在代码中所使用的那样


    您是否在编译时将DynamicTestJar.jar放在类路径中,而不是在运行程序时?编译时不要将其放在类路径中,这样编译器会以静态方式向您显示您在哪里使用JAR。

    您在运行时动态加载JAR
    DynamicTestJar.JAR
    ,但在编译代码时将其添加到类路径中

    因此,当默认类加载器尝试加载
    main()
    的字节码时,它在类路径上找不到
    MyException
    ,并引发异常。这发生在DynamicJarLoader.loadFile(“../DynamicTestJar.jar”);`被处决了


    因此,当加载需要动态JAR的类时,必须确保动态JAR中的类在当前活动的类加载器中可用。您可以在以后将JAR添加到类路径中,尤其是在从中导入内容的类中。

    在Java中,所有类都由类加载器和类的FQN唯一标识

    类加载器是分层的,这意味着动态加载的类可以访问其父类的所有类,但父类不能直接访问其类

    现在,如果您的子类加载器定义了一个扩展父类的类,那么父类的代码只能通过反射或父类引用该类

    如果您认为所有Java代码都是反射的,那么这就更容易了。即:

    Class.forName("MyException")
    

    当前类没有访问子类加载器的权限,因此无法执行此操作。

    感谢您的回答!有可能我把事情搞砸了,但是考虑这两个事实:I)<代码> TestClass <代码>,它与“代码> MyExtExt/Cuth>”处于同一个包中。我刚刚检查了jar文件,
    MyException.class
    就是它应该在的地方。ii)当我离开
    DynamicTestJar.jar
    Java可以找到它的地方(例如lib/)时,程序运行(只是检查了它)。它也从NetBeans运行。只有当我删除jar并将其放在Java看不到的地方(在本例中,“…”)时,问题才会显现出来!这只是可能的最简单片段
    catch(MyException e) { }
    
    Class.forName("MyException")