如果在不同的目录中写入两个不区分大小写的公共Java类,那么这两个类在运行时不可用。 (我在Windows,Mac和Linux上使用HotSpot JVM的几个版本测试了这一点,如果有其他JVM可以同时使用它们,我不会感到惊讶。)例如,如果我创建一个名为A的类和一个名为A的类:
// lowercase/src/testcase/a.java
package testcase;
public class a {
public static String myCase() {
return "lower";
}
}
// uppercase/src/testcase/A.java
package testcase;
public class A {
public static String myCase() {
return "upper";
}
}
如果尝试我调用两个类的myCase如此:
System.out.println(A.myCase());
System.out.println(a.myCase());
typechecker成功,但是当我运行类文件生成的代码直接上面我得到:
Exception in thread “main” java.lang.NoClassDefFoundError: testcase/A (wrong name: testcase/a)
在Java中,名称通常区分大小写。一些文件系统(例如Windows)不区分大小写,所以我不惊讶上述行为发生,但似乎是错误的。不幸的是,Java规范是奇怪的非关于哪些类是可见的。 Java Language Specification (JLS), Java SE 7 Edition(第6.6.1节,第166页)说:
If a class or interface type is declared public, then it may be accessed by
any code, provided that the compilation unit (§7.3) in which it is declared is
observable.
在第7.3节中,JLS以非常模糊的术语定义了编译单元的可观察性:
All the compilation units of the predefined package java and its subpackages lang
and io are always observable. For all other packages, the host system determines which compilation units are observable.
The following steps are used to load and thereby create the nonarray class or
interface C denoted by [binary name] N using the bootstrap class loader […]
Otherwise, the Java virtual machine passes the argument N to an invocation of a
method on the bootstrap class loader to search for a purported representation of C
in a platform-dependent manner.
所有这些导致四个问题按重要性的降序排列:
>有没有任何保证哪些类可以通过每个JVM中的默认类加载器加载?换句话说,我可以实现一个有效的,但退化的JVM,不会加载任何类,除了java.lang和java.io中的那些?
>如果有任何保证,上述示例中的行为是否违反了保证(即行为是否是错误)?
>有没有办法使HotSpot同时加载a和A?编写自定义类加载器工作?