奇怪的Java类路径/类加载器行为

时间:2012-02-29 16:53:16

标签: java classpath classnotfoundexception

在加载引用其他在运行时不可用的类的类文件时,我有一个非常奇怪的Java类路径行为。

加载一个具有(在运行时未触及的方法)的类,该类调用另一个类的构造函数,该类具有一个参数,该参数被转换为继承参数类的类,如果只引用了参数类的类未找到异常要加载的类,但该类的方法中没有引用的其他类在类路径中。

我正在使用以下java:

java version "1.6.0_18"
Java(TM) SE Runtime Environment (build 1.6.0_18-b07)
Java HotSpot(TM) 64-Bit Server VM (build 16.0-b13, mixed mode)
(Windows Server 2008 R2)

以下是一个示例:

public class A
{
  public static void main(String[] args)
  {
    System.out.println("it works");
  }

  public void foo()
  {
    new B((D)null);
  }
}

public class B
{
  public B(C c) {
  }
}

public class C
{
}


public class D extends C
{
}

现在我编译类,如果我在类路径中执行包含所有类文件的类A,它会产生“它工作”。

如果我从类路径中删除了除A类之外的所有类,则会发生以下错误:

Exception in thread "main" java.lang.NoClassDefFoundError: C
Caused by: java.lang.ClassNotFoundException: C
        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)
Could not find the main class: A.  Program will exit.

尽管在运行时永远不需要C类。

以下星座作品(在A类中替换为“新B((D)null)”:

public class A
{
  public static void main(String[] args)
  {
    System.out.println("it works");
  }

  public void foo()
  {
    D d = (D)null;
    d.toString();
    B b = (B)null;
    b.toString();
    new B(null);
  }
}

public class B
{
  public B(C c) {
  }
}

public class C
{
}


public class D extends C
{
}

以下星座也有效(强制转换为C而不是D; C不继承任何类)

public class A
{
  public static void main(String[] args)
  {
    System.out.println("it works");
  }

  public void foo()
  {
    new B((C)null);
  }
}

public class B
{
  public B(C c) {
  }
}

public class C
{
}


public class D extends C
{
}

这是预期的行为还是Java错误?

2 个答案:

答案 0 :(得分:1)

refer section 5.5,如果“如果运行时的值为null,则允许强制转换”,这就是为什么使用null转换工作。

答案 1 :(得分:0)

我还没有通过JSR,但我的猜测是,当解释器解释一个类文件时,它不会只执行所需的方法,它会完成所有操作。在这种情况下,需要A,如果foo()也被解释,则需要C。所有这些都应该在加载A时发生。所以错误..