在Java中,为什么异常类在';有必要吗?
我正在开发一个动态加载JAR的应用程序,其中包含它使用的一组类的定义。在我尝试捕获动态加载的JAR中的异常派生类之前,一切都很顺利 下面的代码片段显示了问题(在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
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无关:
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")