public class dummy {
public static void main(String[] args) { System.out.println("hello world"); }
public void init() {
//"dummy2" class defined in a different jar
dummy2 d = new dummy2();
try { d.run(); }
//"dummyexception" class defined in a different jar
catch (dummyexception e) { e.printStackTrace(); }
catch (Exception e) { e.printStackTrace(); }
}
public void init2() {
Runnable r = new Runnable() {
@Override
public void run() {
//"dummy2" class defined in a different jar
dummy2 d = new dummy2();
try { d.run(); }
//"dummyexception" class defined in a different jar
catch (dummyexception e) { e.printStackTrace(); }
catch (Exception e) { e.printStackTrace(); }
}
};
}
}
现在在运行之前,我从类路径中删除了依赖jar。
对于方法ClassNotFoundException
中引用的类“dummyexception
”,我得到“init()
”,而不是方法init2()
中的用法。有趣的是,在方法ClassNotFoundException
中引用了“dummy2
”类没有“init()
”。
答案 0 :(得分:0)
现在在运行之前,我从类路径中删除了依赖jar。我在方法init()中引用的类'dummyexception'得到'ClassNotFoundException',而不是方法init2()中的用法。
只有在执行init方法时才会加载类dummy2
。尽管dummyexcetion
是一个catch参数,因此JVM将此类作为java方法处理。 dummyexception
类的全名放在jvm * .class文件constant_pool中,并在加载dummy
之前检查类可用性。
让我们考虑一个例子:
public class Dummy {
public void init(){
DummyExternal dummy = new DummyExternal();
try {
dummy.run();
} catch(DummyException e) {
} catch(Exception e){ }
}
public void init2(){
new Runnable() {
@Override
public void run() {
DummyExternal dummy = new DummyExternal();
try {
dummy.run();
} catch(DummyException e) {
e.printStackTrace();
} catch(Exception e){}
}
}.run();
}
public static void main(String[] args){
System.out.println("hello world");
}
}
public class DummyException extends RuntimeException {
private static final long serialVersionUID = 2049347223914508696L;
static {
System.out.println("DummyException");
}
}
public class DummyExternal implements Runnable {
static {
System.out.println("DummyExternal");
}
@Override
public void run() {
System.out.println("DummyExternal");
}
}
在输出中我们将:
-rw-r - r-- 1 taky staff 756B May 19 08:26 Dummy $ 1.class
-rw-r - r-- 1 taky staff 956B May 19 08:26 Dummy.class
-rw-r - r-- 1 taky staff 545B May 19 08:26 DummyException.class
-rw-r - r-- 1 taky staff 569B May 19 08:26 DummyExternal.class
命令java Dummy
打印hello world
。因此,没有加载DummyExternal
或DummyException
类。
删除DummyExternal
类文件:rm DummyExternal.class
。 java Dummy
的结果不会改变。
我们删除DummyException
类文件:rm DummyException.class
。
执行java Dummy
后,我们收到了有趣的堆栈跟踪。
Exception in thread "main" java.lang.NoClassDefFoundError: DummyException
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2442)
at java.lang.Class.getMethod0(Class.java:2685)
at java.lang.Class.getMethod(Class.java:1620)
at sun.launcher.LauncherHelper.getMainMethod(LauncherHelper.java:494)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:486)
Caused by: java.lang.ClassNotFoundException: DummyException
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
... 6 more
这种行为是因为异常处理机制。如果class是catch参数,则生成异常处理程序,应在异常处理时解析。异常处理机制与方法调用类似,ClassLoader在类加载之前从常量池解析DummyException
。
答案 1 :(得分:0)
这里推测 - 方法正在按字典顺序验证,并且对于每个方法,异常处理程序在局部变量之前进行验证。
答案 2 :(得分:0)
如果我理解正确,您首先通过提供所有依赖jar
文件来编译您的类。这就是你的课程成功编译的原因。然后在运行程序之前删除了所有依赖的jar
文件。然后你就出错了。
我对此的看法:
据我所知,您不应该收到任何错误,因为使用依赖 jar的init()
和init2()
并未被任何函数调用。
未调用的函数与错误生成之间的关系是什么?
编译类时, JVM 会创建类文件。在这些类文件中, JVM 通过搜索symbolic string references
中的类来创建classpath
来调用方法和类。如果找不到引用的类,则在编译时会出现错误,并且您的类将无法编译。如果找到它,那么编译成功,然后 JVM 在类文件中添加symbolic string references
。此时没有实际的pointer to methods and classes
。
现在,当您运行程序时,您可以在类文件中以symbolic string references
的形式找到对方法的调用。此时,这些symbolic references
会转换为actual pointers to classes and methods
。此时,您的class loader
将搜索那些依赖类 only if
从某种方法调用引用的方法。如果它在类路径中找不到依赖类,则会生成错误。 注意:如果未调用方法, class loader
将不会搜索依赖类。 Symbolic instructions
将被忽略,不会生成任何错误。
您的情况会怎样?
我看不到您的init()
和init2()
被任何人调用。这意味着class loader
无需找到dependent jars
和create pointer to these methods
。这意味着您不应该收到任何错误 Unless
正在调用这些方法。