有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

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

如果类路径中只有要加载的类,而该类的方法中没有引用其他类,则加载一个类(在运行时为非接触方法),该类调用另一个类的构造函数,该类的构造函数的参数被强制转换为继承该参数类的类,从而导致parameter类的“未找到类”异常

我正在使用以下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)空)”:

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 bug


共 (2) 个答案

  1. # 1 楼答案

    refer section 5.5,如果“如果运行时的值为null,则允许强制转换”,这就是null强制转换工作的原因

  2. # 2 楼答案

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