为什么Java允许我们编译名称与文件名不同的类?


170

我有一个文件Test.java和其中的以下代码。

public class Abcd
{
        //some code here

}

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

Java背后的原因是,允许我们编译一个与文件名不公开的文件名不同的类名。

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


28
因为Java。(因为它不是公开的,并且不必遵循相同的命名约定。除此之外,您还需要询问发明它的人。)
Dave Newton 2013年

2
我怀疑是否有一个“很好的解释”。这是公共班级的要求,但对于非公共班级则认为没有必要。
Kayaman

2
好像是一个类似的问题: stackoverflow.com/questions/7633631/…–
sanket

4
为什么要对这个问题进行如此多的投票,首先是它重复的问题:stackoverflow.com/questions/7633631/…–
GM Ramesh

2
@ Ramesh:这个问题的标题和内容更好..(比其他类似的问题更好)
Jayan

Answers:


325

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

许多类(例如事件侦听器)仅在本地使用,并且Java的最早版本不支持嵌套类。如果不放宽“文件名=类名”规则,则每个此类都将需要自己的文件,不可避免的结果是小.java文件的无休止扩散和紧密耦合的代码的分散。

Java引入嵌套类后,此规则的重要性就大大降低了。今天,您可以浏览成百上千个Java文件,而永远不会选择利用它的文件。


60
+1,实际上提供了一个原因,这就是问题。
戴夫·牛顿

4
尤其是对历史信息+1-我怀疑随着嵌套/匿名类的出现,如果现在要做出相同的决定(不关心向后兼容性),那么在每个嵌套类中只允许一个顶级类就更有意义了。文件。
Michael Berry

1
@ berry120可能很不错,因为此限制使编译时的文件搜索复杂化。
Marko Topolnik 2013年

3
@Val否认其他人宁愿使用文本编辑器和CLI工具进行开发,因为您喜欢的IDE就像您创建IDE毫无意义一样傻,因为您可以在没有IDE的情况下进行开发。优秀的开发人员使用两种方法来创建高质量的代码。而且,唯一比所有开发人员都满意的可能性要小得多,那就是,我们所有人都同意唯一的最佳编程语言是什么。
Dan在火光旁摆弄

5
Emacs(或Vim,挑毒)和Unix Shell实用程序的结合也许不像现代IDE那样随您所愿,它们当然更难学,但与之相比,它们具有两个压倒性的优势我尝试过的每个IDE:无论代码库多大,它们都不会崩溃,并且可以跟上我的输入。
zwol 2013年

80

原因与门板相同。如果某人正式居住在办公室(已宣布为公众),则其姓名必须在门标签上。像“亚历克斯·琼斯”或“侦探科伦坡”。如果有人只是去房间,与官员交谈或打扫地板,则不必将他们的名字正式放在门上。取而代之的是,门可以显示“实用程序”或“会议室”。

正式名称或MyClass.java 会议室或Test.java


4
绝对是一个有趣的类比;稍加解释一下如何直接关联可能会更好。OP可能很难建立连接(尽管我完全理解)
Andrew Barber

4
@AndrewBarber我不认为这种类比真的合适,因为它没有为一个公共类建模,而是与多个软件包专用类共享文件。就像门牌上写着“ Heather Santee,经理”,但房间实际上容纳了Heather和她的两位秘书。
Marko Topolnik

@MarkoTopolnik我不应该参与其中;我的类比太可怕了!;)
Andrew Barber 2013年

无论如何,我想写@AndrewBarber; 您只是推了一下:)这个类比也未能表达出最尖锐的担忧:仅由于此功能,编译器必须解析所有文件以发现所有类,否则它将可以读取目录列表并知道所有名称顶级课程。
Marko Topolnik

@AndrewBarber,这个比喻完全符合目录的想法,在长长的走廊上,您只要看一眼门板就可以快速找到一个人,而无需进入每个房间并询问。
exebook 2013年

29

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


20
但是“ Java允许的背后原因是什么?”
Marko Topolnik 2013年

@MarkoTopolnik因为它不会阻止我们:D
Maroun

8
@MarounMaroun但是不阻止我们的背后原因是什么?
Marko Topolnik 2013年

@Marko Java允许在同一文件中定义多个类(只要其中一个是公共的即可)。由于同一软件包中的所有类都必须具有不同的名称,因此除了允许非公共类具有文件名以外的其他名称,没有其他选择。
isnot2bad 2013年

2
我的2分钱:也许是这样设计的,以便在classpath中更快地定位类。按照这种约定,检查文件名/路径足以进行类发现。没有这个约定,类路径类加载器可能需要打开并解析文件才能找到类
Andrei Nicusan 2013年

13

我认为允许它们是嵌套类的先决条件。特别是,匿名类极大地减少了所需的.java文件数量。如果没有对此的支持,您将需要在与使用它们的主类不同的单独文件中的许多单方法接口实现。(我特别考虑动作监听器)

Oracle网站上的Nested Classes Java教程对所有嵌套类都有很好的解释,其中每个示例都有示例。还有一个有用的理由,我在此引用:

为什么要使用嵌套类?

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

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

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

  • 这可能会导致代码更具可读性和可维护性:在顶级类中嵌套小类会使代码更靠近使用位置。

(强调我的)

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


如果一个类型仅在另一种类型内有用,而前一种类型的实例与后一种类型的实例没有关联,该怎么办?
2013年

嵌套类是Java 1.2执行lambda或“一切都是对象时的一流函数”的方法。这是在1.8语法中更改的。当我们要在Java的Type系统中为代数数据类型建模时,也可以使用它们。
鹰眼

12

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


4

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

或假设您碰巧有一个名为ABCD的类和一个Abcd类(让我们进入一个坏主意:它可能会发生),然后将该程序移植到不区分大小写的文件系统中。现在,您不仅必须重命名文件,而且还必须重命名类!

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

如果您理性地探索了要求文件名跟随类名的含义,那么您会发现这是一个坏主意。


我同意您所说的话,但是我不知道它特别回答了这个问题,只是在某种程度上,可以通过允许将非公共类名与文件名。顺便说一句,关于区分大小写,如果我获得一种语言,在任何范围内都Foo被宣布,标识符FOOfoofOo,等会全部“未定义”,即使他们在外范围内的存在。这样的设计将消除文件名区分大小写的问题。
2013年

3

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


0

由于一个Java文件可以包含多个类,因此一个Java文件中可能有两个类。但是,如果Java文件包含一个公共类,则它必须包含一个与文件名同名的类。


不,该规则仅适用于公共课程。
Deadboy
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.