Java延迟加载异常

时间:2013-04-18 16:07:37

标签: java exception lazy-loading

我知道在Java中,类是以惰性方式加载的,因此在使用它们之前不会加载它们。由于某种原因,异常是否被区别对待我刚刚遇到一种情况,即异常类中出现ClassNotFound异常,即使没有抛出任何异常。

示例:

public class A {    

  public static void main(String[] args) {

      if( args.length == 1 ){
          new C();
      }

      if( args.length > 2 ){

//          try {
//              B.throwAnException();
//          } catch (com.google.protobuf.InvalidProtocolBufferException e) {
//              e.printStackTrace();
//          }
     }
  }

}

B组:

import com.google.protobuf.InvalidProtocolBufferException;

public class B {

  static{
    System.out.println( "Load Class B" );
  }

  static void throwAnException() throws InvalidProtocolBufferException{
    throw new com.google.protobuf.InvalidProtocolBufferException("jkl");
  }

}

C类:

public class C {

  static{
    System.out.println( "Load class C" );
  }

}

当我用一个参数运行这样的程序时,我得到:

$java A arg1
Load class C

但是,如果我取消注释A类中的try / catch,我会得到:

$ java A arg1
Exception in thread "main" java.lang.NoClassDefFoundError: com/google/protobuf/InvalidProtocolBufferException

为什么Java在没有抛出异常/未加载类时尝试加载异常类?

4 个答案:

答案 0 :(得分:2)

VM可能需要准备异常跳转表,这需要catch子句中提到的所有异常类型。必须在第一次调用方法之前设置它。

如果您的计划是

    if( args.length > 2 )
        throw new InvalidProtocolBufferException();

    if( args.length > 2 )
        try {
            B.throwAnException();
        } catch (Exception e) {
            e.printStackTrace();
        }

它会没事,因为异常类型没有出现在catch子句中。


JLS实际上没有强制执行延迟类加载的方式 - 它可以尽可能地懒惰,另一方面,如果VM选择预先加载所有类,并且如果它不能这样做则保释,它也是JLS允许。见http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.1.2

  

初始链接时,解决步骤是可选的。实现可以解析来自非常早期链接的类或接口的符号引用,甚至可以递归地解析来自进一步引用的类和接口的所有符号引用。 ...............   实现可以改为仅在主动使用时才选择解析符号引用.......如果程序执行中涉及的类或接口,则可能在程序执行之前发生加载和链接错误。 class Test或任何其他递归引用的类和接口

但是,JLS对类初始化何时发生非常严格。因此,在您的示例中,异常类将尽早加载,但在达到new InvalidProtocolBufferException()之前不得进行初始化。

答案 1 :(得分:0)

JVM将尝试加载刚刚加载的类引用的类。即它会尝试并解决所有可见的问题。

在上面的示例中,我怀疑您是针对Google库编译的,但是您没有将其包含在运行时CLASSPATH中。

答案 2 :(得分:0)

您正在调用引用缺少的类的方法。当你运行一个方法(如果不是更早)时,必须解决方法中引用的所有类 - 换句话说,延迟加载并不像你想象的那样懒惰。

答案 3 :(得分:0)

  

在JVM中加载类是递归的。加载类时,所有引用的类都将在之前加载。

InvalidProtocolBufferException引用了

A。加载A时,将加载所有引用的类。