0
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的类 ' '而不是方法中的用法。有趣的是,在方法中引用的类 '' 没有 '' 。dummyexceptioninit()init2()ClassNotFoundExceptiondummy2init()

4

3 回答 3

0

现在在运行之前,我从类路径中删除了依赖 jar。对于方法 init() 中引用的类“dummyexception”而不是方法 init2() 中的用法,我得到了“ClassNotFoundException”。

dummy2只有在执行 init 方法时才会加载类。尽管dummyexcetion是一个catch参数,所以JVM处理这个类,作为java方法。类的全名dummyexception放在 jvm *.class 文件constant_pooldummy中,JVM 在加载之前检查类的可用性。

让我们考虑一个例子:

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 工作人员 756B 5 月 19 日 08:26 Dummy$1.class

-rw-r--r-- 1 taky 工作人员 956B 5 月 19 日 08:26 Dummy.class

-rw-r--r-- 1 taky 员工 545B 5 月 19 日 08:26 DummyException.class

-rw-r--r-- 1 taky 员工 569B 5 月 19 日 08:26 DummyExternal.class

命令java Dummy打印hello world。所以没有DummyExternalDummyException类被加载。

删除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 参数,则生成异常处理程序,在处理异常时应解决该异常处理程序。异常处理机制类似于方法调用和类加载器DummyException在类加载之前从常量池中解析。

于 2013-05-18T07:38:58.260 回答
0

这里的推测 - 方法正在按字典顺序进行验证,并且对于每个方法,异常处理程序在局部变量之前进行验证。

于 2013-05-18T09:42:27.550 回答
0

如果我理解正确,您首先通过提供所有依赖jar文件来编译您的类。这就是您的课程编译成功的原因。jar然后在运行程序之前删除了所有依赖文件。然后你得到一个错误。

我对此的看法:

根据我的说法,你不应该得到任何错误,因为使用依赖init()jar 的and没有被任何函数调用。init2()

未调用函数与错误生成之间的关系是什么?

编译类时,JVM会创建类文件。在这些类文件中,JVM通过symbolic string referencesclasspath. 如果它没有找到引用的类,您将在编译时收到错误,并且您的类将无法编译。如果找到它,那么您的编译成功,然后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 jarsand create pointer to these methods。这意味着您不应该Unless在调用这些方法时遇到任何错误。

于 2013-05-19T01:48:08.493 回答