Java类名的区分大小写

如果在不同的目录中写入两个具有相同大小写不敏感的公共Java类,那么这两个类在运行时就不可用。 (我在Windows,Mac和Linux上用HotSpot JVM的几个版本testing过,如果有其他的JVM在同一时间使用,我不会感到惊讶)。例如,如果我创build一个名为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"; } } 

包含上面代码的三个eclipse项目可以从我的网站上获得 。

如果尝试我这样调用两个类的myCase

 System.out.println(A.myCase()); System.out.println(a.myCase()); 

typechecker成功,但是当我直接运行上面的代码生成的类文件时,我得到:

线程“main”中的exceptionjava.lang.NoClassDefFoundError:testcase / A(错误名称:testcase / a)

在Java中,名称通常是区分大小写的。 一些文件系统(如Windows)不区分大小写,所以我不惊讶上述行为发生,但似乎是错误的 。 不幸的是,Java规范很奇怪,不能确定哪些类是可见的。 Java语言规范(JLS),Java SE 7版本 (第166页的6.6.1节)说:

如果一个类或接口types被声明为public,那么它可以被任何代码访问,只要它被声明的编译单元(§7.3)是可观察的。

在第7.3节中,JLS定义了一个非常模糊的编制单位的可观察性:

预定义的Java包及其子包lang和io的所有编译单元都是可观察的。 对于所有其他包, 主机系统确定哪些编译单元是可观察的

Java虚拟机规范同样含糊(5.3.1节):

下面的步骤用于加载并由此使用引导类加载器[…]来创build由[二进制名称] N表示的非数组类或接口C。否则,Java虚拟机将参数N传递给调用方法引导类加载器以平台相关的方式searchC的声称表示。

所有这些导致四个问题按照重要性的降序排列:

  1. 每个JVM中的默认类加载器可以加载哪些类可以加载吗? 换句话说,我可以实现一个有效的,但退化的JVM,不会加载任何类,除了在java.lang和java.io中的类吗?
  2. 如果有任何保证,上面的例子中的行为是否违反了保证(即行为是一个错误)?
  3. 有没有办法让HotSpot同时加载aA ? 会写一个自定义类加载器的工作?
  • 在每个JVM中,有没有关于哪些类可以通过引导类加载器加载的保证?

语言的核心部分,以及支持的实现类。 不保证包括你写的任何课程。 (普通的JVM将类加载到一个独立的类加载器中,而实际上,普通的引导加载器通常将其类从JAR中加载出来,因为这样比部署一个大的旧的目录结构更有效。

  • 如果有任何保证,上面的例子中的行为是否违反了保证(即行为是一个错误)?
  • 有没有办法让“标准”的JVM同时加载一个和A? 会写一个自定义类加载器的工作?

Java通过将类的全名映射到文件名中加载类,然后在类path中search该文件名。 因此, testcase.a进入testcase/a.classtestcase.A进入testcase/A.class 。 有些文件系统把这些东西混合起来,并且在需要的时候可以为另一个文件系统提供服务。 其他人则正确(特别是JAR文件中使用的ZIP格式的变体是完全区分大小写和便携的)。 Java没有办法做到这一点(尽pipeIDE可以通过保持.class文件远离本地FS来处理它,但我不知道是否真的有这么做,JDK的javac肯定不是那么聪明)。

然而,这不是唯一需要注意的地方:类文件在内部知道他们正在讨论的是什么类。 文件中没有预期的类只是意味着加载失败,导致您收到NoClassDefFoundError 。 你得到的是一个问题(至less在某种意义上是错误的部署),被强烈检测和处理。 从理论上讲,你可以build立一个类加载器,通过继续search来处理这些事情,但是为什么呢? 将类文件放在JAR中会解决更强大的问题。 那些处理正确。

更一般地说,如果你真的遇到了这个问题,可以考虑在Unix上使用区分大小写的文件系统(build议使用像Jenkins这样的CI系统)进行生产构build,并找出哪些开发人员命名类只是区分大小写并让他们停下来,因为它是非常混乱!

多纳的好的解释没有多less补充,但让我简单地思考一下这句话:

…具有相同大小写不敏感名称的Java类

一般来说名称和string从来都不区分大小写只有解释才可以。 其次,Java不做这样的解释。

所以,你想到的一个正确的措辞是:

在不区分大小写的文件系统中,其文件表示forms的Java类具有相同的名称…

不要只考虑文件夹。

使用显式的不同名称空间(“包”)为您的类,也许使用文件夹来匹配您的类。

当我提到“软件包”时,我并不是指“* .JAR”文件,而只是以下概念:

 package com.mycompany.mytool; // "com.mycompany.mytool.MyClass" public class MyClass { // ... } // class MyClass 

当你没有为你的代码指定一个包的时候,java工具(编译器,IDE等等)假定为所有的包都使用相同的全局包。 而且,在几个类似的情况下,他们有一个文件夹列表,在哪里寻找。

包就像代码中的“虚拟”文件夹一样,并且适用于您的类path上的所有包,或者Java的安装。 您可以拥有几个具有相同ID的类,但是,如果它们位于不同的包中,并指定要查找的包,则不会有任何问题。

只是我的2美分,为你的一杯Java咖啡