在Java中,引用不存在的类/方法的动态加载类何时会失败?

在Java中,引用不存在的类/方法的动态加载类何时会失败?,java,java-me,Java,Java Me,假设我动态加载一个Java类C,该类引用不存在的类/方法。当为较新版本的Java编写C时,可能会出现这种情况。当C加载时,或者当调用不存在的类/方法的方法运行时,它会失败吗?VM是否会改变这种情况?包括Java的其他版本,如Java ME?它将无法加载。这可能真的很烦人,但当然这还不够小心。解决这个问题的方法是根据您知道的其他可用定义动态加载不同的类。至少在普通的旧Java上,我发现在引用损坏的类或方法时,它会失败: 我自己最近的经历中的例子: 我使用一个Java编辑器(用Java编写)和一个简

假设我动态加载一个Java类
C
,该类引用不存在的类/方法。当为较新版本的Java编写
C
时,可能会出现这种情况。当
C
加载时,或者当调用不存在的类/方法的方法运行时,它会失败吗?VM是否会改变这种情况?包括Java的其他版本,如Java ME?

它将无法加载。这可能真的很烦人,但当然这还不够小心。解决这个问题的方法是根据您知道的其他可用定义动态加载不同的类。

至少在普通的旧Java上,我发现在引用损坏的类或方法时,它会失败:

我自己最近的经历中的例子:

我使用一个Java编辑器(用Java编写)和一个简单的插件系统。我已经更新了编辑器,但是使用了一个插件,用旧版本的编辑器编译,它仍然引用了一个类,为了简洁起见,我们将其称为
Foo
,它从一个内部类移到了一个包中

当我调用插件时,它没有失败,直到它尝试创建
Foo
的实例。由于Foo不在插件代码所说的位置,它抛出了一个错误

另一方面,至少在Java 1.5和Java 1.6这样的Java版本之间,您通常不必担心它们会删除或移动某些东西,因为如果您弄乱了一个已建立的API,人们会尖叫血腥的谋杀

什么时候会失败

C一加载

否。仅当加载时它引用不存在的类(即,您有该类型的类属性)

或者当调用不存在的类/方法的方法运行时

对。情况就是这样

例如,这运行良好

C:\>more > A.java
class A {}
^C
C:\>more > B.java
class B {
   public void method() {
      A a = new A();
    }
    public void other() {
       System.out.println("Hello there");
    }
    public static void main( String ... args ) {
        B b = new B();
        b.other();
    }
}

C:\>javac A.java B.java

C:\>erase A.class

C:\>java B
Hello there
类B是由java加载的,但是由于没有使用
method
的代码,所以它工作得很好

与之相反:

C:\>more > A.java
class A {}

C:\>more > B.java
class B {
   void method() {
      A a = new A();
   }
   public static void main( String ... args ) {
       B b = new B();
       b.method();
   }
}
^C
C:\>javac A.java B.java

C:\>erase A.class

C:\>java B
Exception in thread "main" java.lang.NoClassDefFoundError: A
        at B.method(B.java:3)
        at B.main(B.java:7)
Caused by: java.lang.ClassNotFoundException: A
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        ... 2 more
失败,因为B尝试访问A。

此步骤称为“解析”,加载该类引用的其他类

语言规范允许在执行此步骤时进行更改。在VM的开始,递归地解析直接或间接从主类引用的所有类,这是最迫切需要做的。或者它可以最懒地完成,只在绝对必要时解析类

我对服务器JVM的经验是,它尽可能晚地完成。因此,只要没有执行引用缺少的类的代码,就不会看到任何错误


这还取决于你如何加载你的类
java.lang.Classloader.loadClass(名称)
不进行解析。但是,有一个受保护的方法
loadClass(name,resolve)
,您可以使用它在加载时强制解析。但是,它的确切行为没有很好的文档记录。

您知道它在其他JVM(如Java ME)上是否也能以同样的方式工作吗?我不知道,但它应该这样做。我想要花几分钟才能弄清楚。