当前位置: 首页 > 知识库问答 >
问题:

Java类名的大小写敏感性

常英资
2023-03-14

如果在不同的目录中写入两个具有相同不区分大小写名称的公共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";
    }
}

我的网站上提供了三个包含上述代码的eclipse项目。

如果尝试我调用myCase在两个类上像这样:

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

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

线程“main”java中出现异常。lang.NoClassDefFoundError:testcase/A(错误名称:testcase/A)

在Java,名称通常区分大小写。一些文件系统(例如:Windows)不区分大小写,所以出现上述行为并不奇怪,但似乎是错误的。不幸的是,Java规范奇怪地不确定哪些类是可见的。Java语言规范(JLS),JavaSE 7版(第6.6.1节,第166页)说:

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

在第7.3节中,JLS用极其模糊的术语定义了编译单元的可观测性:

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

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

以下步骤用于加载,从而使用引导类加载器[...]创建由[二进制名称]N表示的非数组类或接口C否则,Java虚拟机将参数N传递给引导类加载器上的方法调用,以依赖于平台的方式搜索所谓的C表示形式。

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

  1. 对于每个JVM中的默认类加载器可以加载哪些类,是否有任何保证?换句话说,我可以实现一个有效但退化的JVM,它不会加载除java中的类以外的任何类。语言和java。伊奥
  2. 如果有任何保证,上述示例中的行为是否违反了保证(即,该行为是一个bug)
  3. 有没有办法同时使热点加载aa?编写自定义类装入器是否可行

共有3个答案

皇甫智明
2023-03-14

不要只考虑文件夹。

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

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

package com.mycompany.mytool;

// "com.mycompany.mytool.MyClass"

public class MyClass
{
   // ...
} // class MyClass

当您没有为代码指定包时,java工具(编译器,即,无论什么)假定对所有代码使用相同的全局包。对于几个类似的类,它们有一个文件夹列表,可以在其中查找。

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

只要我的2美分,买你的一杯爪哇咖啡

巫煌
2023-03-14

多纳尔精辟的解释没有什么可补充的,但让我简单地思考一下这句话:

...Java具有相同不区分大小写名称的类...

通常,名称和字符串本身从来都不区分大小写,只有这样才能进行解释。第二,Java没有这样的解释。

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

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

百里光熙
2023-03-14
  • 对于每个JVM中的引导类加载器可以加载哪些类,是否有任何保证

语言的核心部分,以及支持的实现类。不保证包含您编写的任何类。(普通的JVM将您的类加载到一个独立于引导加载程序的类加载程序中,事实上,普通的引导加载程序通常从JAR中加载它的类,因为这使得部署比一个充满类的大型旧目录结构更高效。)

  • 如果有任何保证,上述示例中的行为是否违反了保证(即,该行为是一个bug)

Java通过将类的全名映射到然后在类路径上搜索的文件名来加载类。因此testcase. a转到testcase/a.classtestcase。a转到testcase/A. class。有些文件系统把这些东西混在一起,当需要一个时,可能会提供另一个。其他人做对了(特别是,JAR文件中使用的ZIP格式的变体是完全区分大小写和可移植的)。Java对此无能为力(尽管IDE可以通过将. class文件远离本机FS来处理它,但我不知道是否有人真的这样做,JDK的javac大多数人肯定没那么聪明)。

然而,这并不是这里要注意的唯一一点:类文件在内部知道它们谈论的是什么类。文件中缺少预期的类只意味着加载失败,从而导致您收到的NoClassDefFoundError。您得到的是一个问题(至少在某种意义上是一个错误部署),它被检测到并得到了可靠的处理。从理论上讲,您可以构建一个类加载器,通过不断搜索来处理这些事情,但为什么要麻烦呢?将类文件放在JAR中将更可靠地修复问题;这些是正确处理的。

更一般地说,如果你经常遇到这个问题,那就在一个具有大小写敏感文件系统的Unix上进行生产构建(推荐像Jenkins这样的CI系统),并找到哪些开发人员用大小写差异命名类,并让它们停止这是非常令人困惑的!

 类似资料:
  • 在执行MySQL 数据库给数据表改名时,发现报错,如下: 从提示中可以看出 blog_comment,表已经存在,可登录 MySQL 客户端查看数据表,并没有看到这张表。 提示中所说目标表并不存在。手动执行改名SQLRENAME TABLE blog_Comment TO blog_comment;,报同样错误:Table 'blog_comment' already exists。 从网上找一些

  • 除了 Java 类与属性的名称外,查询语句对大小写并不敏感。 所以 SeLeCT 与 sELEct 以及 SELECT 是相同的,但是 org.hibernate.eg.FOO 并不等价于 org.hibernate.eg.Foo 并且 foo.barSet 也不等价于 foo.BARSET。 本手册中的 HQL 关键字将使用小写字母。很多用户发现使用完全大写的关键字会使查询语句的可读性更强,但我

  • 问题内容: 默认情况下,django的url解算器似乎执行区分大小写的搜索来解析url,并区分’/ Login’和’login’。我的网址格式如下。 谁能指导我,如何使Django URL不区分大小写? 问题答案: 只需放在每个字符串的开头,即: 告诉每个RE不区分大小写地匹配

  • 问题内容: 我正在尝试考虑在PHP中实现不区分大小写的file_exists函数的最快方法。我最好的选择是枚举目录中的文件,并进行strtolower()与strtolower()的比较直到找到匹配项? 问题答案: 我使用注释中的源代码来创建此功能。返回完整路径文件(如果找到),否则返回FALSE。 在文件名中的目录名称上不区分大小写。

  • 问题内容: 这是我的mysql表的架构,即时通讯使用mysql 5 需要敏感的UNIQUE KEY大小写, 它应该允许输入类似(’a’,0)&(’A’,0)的值 尝试将排序规则更改为latin_1和latin_generic_ci 问题答案: 最简单的是在DDL语句上添加, SQLFiddle演示

  • 本文向大家介绍MySQL大小写敏感导致的问题分析,包括了MySQL大小写敏感导致的问题分析的使用技巧和注意事项,需要的朋友参考一下 MYSQL对大小写敏感 见字如面,见标题知内容。你有遇到过因为MYSQL对大小写敏感而被坑的体验吗? 之前看过阿里巴巴Java开发手册,在MySql建表规约里有看到: 【强制】表名、字段名必须使用小写字母或数字 , 禁止出现数字开头,禁止两个下划线中间只 出现数字。数