为什么每个公共课都在一个单独的文件?

我最近开始学习Java,发现很奇怪每个Java类都必须在一个单独的文件中声明。 我是C#程序员,C#不强制执行任何此类限制。

为什么Java会这样做? 有没有devise考虑?

编辑(基于几个答案):

为什么Java在IDE的时代现在不去除这个限制? 这不会破坏任何现有的代码(或将?)。

根据Java语言规范,第三版 :

这个限制意味着每个编译单元最多只能有一个这样的types。 这个限制使Java编程语言的编译器或者Java虚拟机的实现能够轻松地在包中find一个命名的类 ; 例如,公共typeswet.sprocket.Toad的源代码将在湿/链轮目录中的文件Toad.java中find,并且相应的目标代码将在同一目录中的文件Toad.class中find。

重点是我的。

好像基本上他们想把操作系统的目录分隔符翻译成命名空间的点,反之亦然。

所以是的,这是某种devise的考虑。

我刚刚采取了一个C#解决scheme,并做了这个(删除任何文件,其中有多个公共类),并打破了个人文件,这使得生活变得更加容易。

如果你在一个文件中有多个公共类,你有几个问题:

  1. 你是什​​么文件的名字? 其中一个公开课? 别的名字? 人们对于糟糕的解决scheme代码组织和文件命名约定有足够的问题有一个额外的问题。

  2. 另外,当你正在浏览文件/项目浏览器是好东西,不隐藏。 例如,你看到一个文件,然后向下钻取,有200个class级一起玩。 如果你有一个文件一个类,你可以更好地组织你的testing,并感受一个解决scheme的结构和复杂性。

我认为Java得到了这个权利。

从Java的思考

每个编译单元(文件)只能有一个公共类。
这个想法是, 每个编译单元都有一个由公共类表示的公共接口 。 它可以有你想要的支持“友好”类。 如果在编译单元中有多个公共类,编译器会给你一个错误信息。


从规范(7.2.6)

当包被存储在一个文件系统(?7.2.1)中时,主机系统可以select强制执行一个限制,即如果在一个文件中没有find一个types,如果满足以下任一条件,则为扩展名(例如.java或.jav)

  • 该types被声明types的包的其他编译单元中的代码引用。
  • 该types是公开的(因此可以从其他包中的代码访问)。
  • 这个限制意味着每个编译单元最多只能有一个这样的types。
  • 这个限制使Java编程语言的编译器或Java虚拟机的实现可以轻松地在包中find一个命名的类 ; 例如,公共typeswet.sprocket.Toad的源代码将在湿/链轮目录中的文件Toad.java中find,并且相应的目标代码将在同一目录中的文件Toad.class中find。

简而言之:它可能是关于查找类,而无需在类path中加载所有内容。

编辑:“可能select”似乎留下遵循该限制的可能性,“可能”的含义很可能是RFC 2119中描述的(即“可选”)
实际上,这是在这么多的平台上执行的,依靠这么多的工具和IDE,我没有看到任何“主机系统”select执行这个限制。


从“ 曾经的橡树… ”

这很明显 – 就像大多数事情一旦你知道devise原因一样 – 编译器将不得不通过所有的编译单元(.java文件)进行额外的传递,以找出哪些类是在哪里,这将使编译更慢。

(注意:

Oak版本0.2的橡树语言规范 (后文档): 橡树是现在俗称的Java的原始名称,而本手册是橡树(即Java)最早的手册。
有关Java起源的更多历史,请参阅绿色项目和Java(TM)技术:早期历史

这只是为了避免混淆 ,从开发人员的angular度来看,Java是以简单的方式创build的。 你的“主要”类是你的公共类,如果它们在一个同名的文件中,并且在类包中指定的目录中,它们很容易被人发现。

您必须记住,Java语言是在90年代中期开发的, 在IDE进行代码导航和search之前的那几天

如果一个类只被另一个类使用,则将其作为一个私有的内部类。 这样你就可以将多个类放在一个文件中。

如果一个类被多个其他类使用,那么这些类中的哪一个会放入同一个文件? 三个全部? 你最终将所有的课程放在一个文件中

这就是语言devise者决定如何做的。 我认为主要的原因是优化编译器传递 – 编译器不必猜测或parsing文件来定位公共类。 我认为这实际上是一件好事,它使得代码文件更容易find,并且迫使你避免把太多的东西放到一个文件中。 我也喜欢Java如何强制你把你的代码文件放在与包相同的目录结构中 – 这样可以很容易地find任何代码文件。

为什么java在IDE的时代现在不去除这个限制? 这不会破坏任何现有的代码(或将?)。

现在所有的代码是统一的。 当你看到一个源文件,你知道什么期望。 每个项目都是一样的。 如果java要删除这个约定,你必须重新学习你所工作的每一个项目的代码结构,现在你只需要学习一次,然后在任何地方应用。 我们不应该相信IDE的一切。

在一个文件中拥有多个Java顶级类在技术上是合法的。 但是,这被认为是不好的做法,如果你这样做,许多Java工具(包括IDE)不工作。

JLS说:

当包存储在一个文件系统(§7.2.1)中时, 主机系统可以select强制执行一个限制 ,即如果在一个文件中找不到一个types,那么这个编译时错误就是一个编译时错误如果满足以下任一条件,则为扩展名(例如.java或.jav):

  • 该types被声明types的包的其他编译单元中的代码引用。
  • 该types是公开的(因此可以从其他包中的代码访问)。

请注意在JLS文本中使用may 。 这就是说编译器可能会将其视为无效,或者可能不会。 如果您要将源代码级别的 Java代码构build为可移植的,那么这不是一个好的情况。 因此,即使一个源文件中的多个类在你的开发平台上工作,这也是不好的做法。

我的理解是,这个“拒绝许可”是一个devise决定, 部分原因是为了更容易在更广泛的平台上实现Java。 如果(相反)JLS要求所有编译器支持包含多个类的源文件,那么在一个不是基于文件系统的平台上实现Java将会有概念性问题。

在实践中,经验丰富的Java开发人员不会错过能够做到这一点。 模块化和信息隐藏最好使用软件包,类访问修饰符和内部或嵌套类的适当组合。

这个问题不是一个真正的答案,而是一个数据点。

我把我个人的C ++实用程序库的头文件(你可以从这里自己得到)和几乎所有实际声明类的头文件(一些只是声明自由函数)声明多个类。 我喜欢把自己当成一个相当不错的C ++devise者(尽pipe这个库在某些地方有点不起眼 – 我是它的唯一用户),所以我build议至less对于C ++来说,同一个文件中的多个类是正常的甚至是好的做法。

它允许从Foobar.class到Foobar.java更简单的启发式。

如果Foobar可能存在于任何Java文件中,那么您有一个映射问题,这可能最终意味着您必须对所有java文件进行全面扫描才能find该类的定义。

就我个人而言,我发现这是一个奇怪的规则之一,结合在一起的结果是Java应用程序可以增长非常大,仍然坚固。

单个文件中可以有许多公共类。 但是,每个文件的顶级类。 每个文件都可以有许多公共的内部/嵌套类。

我想你喜欢这个链接 – 一个Java文件可以有多个类?