为啥Java允许我们编译一个名称与文件名不同的类?

Posted

技术标签:

【中文标题】为啥Java允许我们编译一个名称与文件名不同的类?【英文标题】:Why does Java allow us to compile a class with a name different than the file name?为什么Java允许我们编译一个名称与文件名不同的类? 【发布时间】:2013-12-10 08:08:16 【问题描述】:

我有一个文件Test.java,里面有以下代码。

public class Abcd

        //some code here


现在该类无法编译,但是当我删除 public 修饰符时,它可以正常编译。

Java 允许我们编译一个与非公开文件名不同的类名的原因是什么。

我知道这是一个新手问题,但我找不到很好的解释。

【问题讨论】:

因为 Java。 (因为它不是公开的,并且不必遵循相同的命名约定。除此之外,您需要询问发明它的人。) 我怀疑是否有“好的解释”。这是公开课的要求,但对于非公开课则被认为没有必要。 似乎是一个类似的问题:***.com/questions/7633631/… 为什么这个问题有这么多赞,首先是它的重复问题:***.com/questions/7633631/… @Ramesh : 这个问题的标题和内容更好..(比其他类似问题) 【参考方案1】:

基本原理是每个.java 文件允许一个以上的***类。

许多类(例如事件侦听器)仅供本地使用,Java 的最早版本不支持嵌套类。如果不放宽“文件名 = 类名”规则,每个此类都会需要自己的文件,这不可避免地会导致小 .java 文件的无限增殖和紧密耦合代码的分散。

Java 引入嵌套类后,这条规则的重要性就大大减弱了。今天,您可以浏览数百个 Java 文件,而不会碰巧找到一个利用它的文件。

【讨论】:

+1,这其实提供了一个原因,也就是问题所在。 +1 尤其是历史信息 - 我怀疑随着嵌套/匿名类的出现,如果现在做出同样的决定(不关心向后兼容性),它会更有意义每个文件只允许一个***类。 @berry120 很可能,因为这个允许在编译时使文件搜索变得复杂。 @Val 否认其他人宁愿使用文本编辑器和 CLI 工具来开发,因为你喜欢的 IDE 存在,就像说创建 IDE 没有意义,因为你可以在没有开发环境的情况下进行开发一样愚蠢他们。优秀的开发人员使用这两种方法来创建高质量的代码;唯一比所有开发人员解决其中一个并唱 kumbaya 的可能性更小的事情是我们都同意最好的编程语言是什么。 Emacs(或 Vim,选择你的毒药)和 Unix shell 实用程序的组合可能不像现代 IDE 那样触手可及,而且它们当然更难学习,但与我尝试过的所有 IDE 相比,它们有两个压倒性的优势:无论代码库有多大,它们都不会崩溃,而且它们可以跟上我的打字速度。【参考方案2】:

原因与门牌相同。如果某人正式居住在办公室(公开),他/她的名字必须在门牌上。像“亚历克斯琼斯”或“科伦坡侦探”。如果有人只是访问房间,与官员交谈或打扫地板,他们的名字不必正式贴在门上。相反,门可以显示“实用程序”或“会议室”。

【讨论】:

绝对是一个有趣的类比;稍微解释一下它是如何直接相关的,可能会更好。 OP 在建立连接时可能会遇到一些困难(尽管我完全理解) @AndrewBarber 我不认为这个类比真的合适,因为它没有模拟一个公共类,与几个包私有类共享文件。这就像门牌上写着“希瑟·桑蒂,经理”,但房间里实际上是希瑟和她的两个秘书。 @MarkoTopolnik 我不应该参与其中;我在类比方面是 A 级可怕! ;) @AndrewBarber 我想写它,无论如何;你只是推了一下 :) 这个类比也没有表达出最严重的担忧:正是由于这个特性,编译器必须解析所有文件以发现所有类,否则它只能读取目录列表并知道所有类的名称***课程。 @AndrewBarber,这个比喻非常符合目录的概念,在长长的走廊里,你只要看一眼门牌就可以快速找到一个人,你不需要进入每个房间问。 【参考方案3】:

Java 规范规定每个文件最多只能有一个公共类。在这种情况下,类名应该与文件名匹配。所有非公共类都可以有任何名称,无论文件名如何。

【讨论】:

但是“Java 允许我们这样做的原因是什么? @MarkoTopolnik 因为它不会阻止我们:D @MarounMaroun 但是不阻止我们的原因是什么? @Marko Java 允许在同一个文件中定义多个类(只要其中一个是公共的)。由于同一个包中的所有类都必须具有不同的名称,因此除了允许非公共类具有文件名之外的名称之外,别无选择。 我的 2 美分:也许它是为了更快地在类路径中定位类而设计的。使用此约定,检查文件名/路径足以进行类发现。如果没有这个约定,类路径类加载器可能需要打开和解析文件才能找到类【参考方案4】:

我认为允许它们是嵌套类的先决条件。匿名类尤其显着减少了所需的 .java 文件的数量。如果不支持这一点,您将需要在它们自己的独立文件中的大量单一方法接口实现与它们所使用的主类。(我特别考虑动作侦听器)

Oracle 网站上的Nested Classes Java 教程中对所有嵌套类都有很好的解释,其中每个都有示例。这也有它们有用的原因,我将引用:

为什么要使用嵌套类?

使用嵌套类的令人信服的原因包括:

这是一种对仅在一个地方使用的类进行逻辑分组的方法:如果一个类仅对另一个类有用,那么将其嵌入该类是合乎逻辑的并将两者保持在一起。嵌套这样的“帮助类”使它们的包更加精简。

增加封装:考虑两个***类 A 和 B,其中 B 需要访问 A 的成员,否则 宣布为私有。通过将 B 类隐藏在 A 类中,A 的成员可以 声明为私有,B 可以访问它们。另外,B本身可以 对外界隐藏。

它可以使代码更具可读性和可维护性:在***类中嵌套小类可以使代码更接近它所在的位置 用过。

(强调我的)

早期我对 Java 规范并不熟悉,但快速搜索显示 Java 1.1 中添加了内部类。

【讨论】:

如果一种类型只在另一种类型中有用,但前一种类型的实例与后一种类型的实例没有关联,该怎么办? 嵌套类是 Java 1.2 执行 lambda 或“当一切都是对象时的第一类函数”的方式。这在 1.8 语法中有所改变。当我们想在 Java 的类型系统中对代数数据类型进行建模时,也会使用它们。【参考方案5】:

我反过来看。自然的情况是程序员独立地选择类名和文件名。可能是为了在编译过程中简化从包外部查找公共类,有一个特殊限制,即公共类必须在具有相应名称的文件中。

【讨论】:

【参考方案6】:

请注意,Java 区分大小写,但文件系统不需要。如果文件的基本名称是“abcd”,但类是“Abcd”,这是否符合不区分大小写文件系统的规则?移植到区分大小写的时候肯定不会。

或者假设您碰巧有一个名为 ABCD 的类和一个 Abcd 类(我们不要认为这是一个坏主意:它可能会发生)并且程序被移植到不区分大小写的文件系统。现在你不仅要重命名文件,还要重命名类,哎呀!

或者如果没有文件怎么办?假设您有一个 Java 编译器,它可以接受标准输入的输入。那么这个类必须命名为“StandardInput”?

如果你理性地探索要求文件名跟在类名后面的含义,你会发现它在多个方面都是一个坏主意。

【讨论】:

我同意你的说法,但我不知道它是否特别回答了这个问题,除非可能通过允许非命名架构来缓解一些由命名架构引起的问题-public 类名与文件名不同。顺便说一句,关于区分大小写,如果我要派生一种语言,则在任何范围内都声明了 Foo,标识符 FOOfoofOo 等都将是“未定义的”,即使它们存在于外部范围内。这样的设计将消除文件名区分大小写的问题。【参考方案7】:

还有一点很多答案都没有指出,如果没有public 声明,JVM 永远不会知道需要调用哪些类的主方法。在一个 .java 文件中声明的所有类都可以具有 main 方法,但 main 方法仅在标记为 public 的类上运行。高温

【讨论】:

【参考方案8】:

因为一个java文件可以包含多个类,所以一个java文件中可能有两个类。但是如果java文件包含公共类,则必须包含与文件名同名的类。

【讨论】:

不,该规则仅适用于公共课程。

以上是关于为啥Java允许我们编译一个名称与文件名不同的类?的主要内容,如果未能解决你的问题,请参考以下文章

我可以编译一个名称与类不同的 java 文件吗?

java有import的类怎么编译

一个java 源文件,可以有多个类,但是只能有一个public修饰的类

java 扩展类与继承类是一样的吗?有啥不同?

为啥 Eclipse 不编译 APT 生成的类?

Java annotation (注解)