【问题标题】:ClassNotFound exception in the catch clausecatch 子句中的 ClassNotFound 异常
【发布时间】:2013-05-18 06:30:05
【问题描述】:
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() 中引用的类 'dummyexception' 而不是方法 init2() 中的用法。有趣的是,在方法 init() 中引用的类“dummy2”没有“ClassNotFoundException”。

【问题讨论】:

  • 您的代码示例在这里值一千字。
  • 谁在打电话给init()init2()
  • @RaviTrivedi 假设 init() 和 init2() 从未调用过
  • @taky,先生,那么他不应该收到此错误,因为仅因为未使用方法而没有发生动态链接。这意味着 JVM 在类文件中不需要将字符串符号引用转换为指向这些方法的实际指针。
  • @RaviTrivedi 我很迷茫,但是当你加载类时,方法会尝试在 catch 声明中分类。可能与JVM内部的异常处理机制有关。

标签: java exception classloader classnotfound


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    我对此的看法:

    根据我的说法,您应该不会收到任何错误,因为 init()init2() 使用 dependent jar,没有被任何函数调用。

    函数不被调用和错误产生有什么关系?

    当您编译类时,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 某些东西正在调用这些方法。

    【讨论】:

      【解决方案3】:

      现在在运行之前,我从类路径中删除了依赖 jar。我得到 'ClassNotFoundException' 是因为方法 init() 中引用的类 'dummyexception' 而不是方法 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 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 5 月 19 日 08:26 DummyException.class

      -rw-r--r-- 1 taky Staff 569B May 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

      【讨论】:

      • 同意你的观点。但最重要的问题是为什么我会为“dummyexception”类而不是“dummy2”类得到“classnotfoundexception”。这两个类都在一个在运行时不可用的依赖 jar 中。而且我尝试单独评论“init()”方法,这次我没有得到任何异常!
      • 谢谢塔基。但是如果我们注释 init() 方法,init2() 不会有任何 'classnotfoundexception',是因为 init2() 中实例化了匿名类吗?
      • @karts 是的,只有在第一次执行 init2() 时才会加载匿名。
      猜你喜欢
      • 2021-09-09
      • 1970-01-01
      • 2013-04-15
      • 1970-01-01
      • 2023-03-25
      • 1970-01-01
      • 2012-06-30
      • 1970-01-01
      相关资源
      最近更新 更多