2013-05-18 40 views
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”在方法init(),而不是在方法init2()使用被引用的类“dummyexception”。有趣的是没有“ClassNotFoundException”为类“dummy2”被referrenced在该方法中init()catch子句中的ClassNotFound异常

+1

您的代码示例在这里值得一千字。 – Perception

+0

谁在调用'init()'或'init2()'? –

+0

@RaviTrivedi假设init()和init2()从来没有调用 – Taky

回答

0

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

dummy2只会在init方法执行时加载。尽管dummyexcetion是一个catch参数,所以JVM处理这个类,就像java方法一样。对于dummyexception类全名被放置到JVM * .class文件constant_pool和JVM检查级别的可用性之前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人员756B 5月19日08:26虚拟$ 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.classjava 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

+0

同意你的观点。但最重要的问题是为什么我会为班级'dummyexception'而不是班级'dummy2'获得'classnotfoundexception'。这两个类都位于运行时不可用的依赖jar中。而且我也试着单独评论“init()”方法,这一次我根本没有得到任何异常! – karts

+0

谢谢塔基。但是如果我们评论init()方法,那么不会是init2()的任何'classnotfoundexception',是因为在init2()中实例化了匿名类吗? – karts

+0

@karts是的,匿名只会在第一次执行init2()时加载。 – Taky

0

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

0

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

我拿到这个:

据我,你不应该得到任何错误,因为init()init2(),其中使用依赖罐子,不被任何函数调用。

函数没有被调用和错误生成之间的关系是什么?

当您编译您的类时,JVM创建类文件。在这些类文件中,JVM通过搜索classpath中的类来创建symbolic string references来调用方法和类。如果它没有找到引用的类,那么在编译时你会得到错误,而你的类将不能编译。如果发现它,那么你的编译是成功的,然后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 jarscreate pointer to these methods。这意味着你不应该得到任何错误Unless东西正在调用这些方法。