繁体   English   中英

为什么 Java 文件中只有 1 个公共 class

[英]Why only 1 public class in Java file

在任何 Java 文件中,为什么我们只能有一个与 Java 文件名相同的公共 class 文件?

它强制所有 Java 代码以某种方式组织,从长远来看,这有助于提高代码的可读性

Java 设计人员选择了一种严格的方法来执行他们的良好设计实践理念,这也是该主题的一部分。 将其与 Perl 中随心所欲的态度形成鲜明对比。

根据这个来源,它是为了高效编译:

在侧边栏中,它解释了原因:“编译器尚未强制执行此限制,尽管它是有效导入包所必需的”

这很明显 - 就像大多数事情一样,一旦你知道设计原因 - 编译器将不得不通过所有编译单元(.java 文件)来确定哪些类在哪里,这会使编译变得更慢.

这同样适用于 IDE 中源文件的导入。 另一个原因是合理的源大小。

这些是规则。 虽然这并不完全正确。 您可以像这样在“主”类中定义内部类:

public class A {  
   public class B {  
       ...  
   }  
}

在任何 java 编译单元(.java 源文件)中,我们只能有一个顶级公共类或接口。

但是每个 src 文件可以有任意数量的默认类/接口。

为什么:

JLS 将选项留给 java 编译器。 并且大多数编译器实现强制文件名与以下内容相同:

(1) 公共类/接口名

(2) 如果有一个 main 方法并且没有公共类,那么任何名称

(3)如果有主方法和公共类,那么主方法应该在那个公共类中

(4) 如果没有公共类和主方法,则任何有效名称可能与文件中的类/接口名称匹配或不匹配。

来自(2):如果允许两个公共类,我们应该给文件两个名字,这对文件系统来说是非常没有意义的。 来自(3):如果允许两个公共类,我们应该有两个对java来说非常没有意义的主要方法

因此,Java 源文件只能有一个公共类。

我认为以上 4 点是编译器强制编译器和 jvm 为编译/加载/链接找到特定的 java 源文件或类文件的工作。 Java 有这样的内置限制,开发人员应该遵循这些限制以获得更好的编程。

资料来源:我的阅读和理解。

为了理解这些限制背后的基本原因,让我们假设编译器没有因为文件名与公共类名不同而产生编译错误。

假设有一个包 A

        A
      /   \
file1.java   file2.java

文件1.java

package A;

class file1
{
  public static void main(String args[])
  {

  }
}

public class file3
{
 public static void main(String args[])
 {

 }
}

现在我们知道,公共类也可以在包外访问,现在开发人员有责任让外部世界访问它。 让我们看看如何:

假设包 A 只包含 Java 文件(没有类文件)并且包 A 之外的某个类尝试访问公共类 file3,编译器将首先尝试查找 file3.class(不可用),然后它会尝试查找 file3.java ( 无法使用 )。 因此,即使 file3 类本质上是公共的,它对外界也是不可见的。 因此,如果编译器限制如果文件包含公共类,则应将其命名为与公共类名相同,则可以解决上述问题,开发人员不必考虑将公共类暴露给外界.

编译器还限制每个Java文件最多只能有一个公共类,这样每个公共类都可以被外界访问。

感谢 Heinz Kabutz 博士和他出色的时事通讯......

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

这是我在课程中经常被问到的一个问题。 到目前为止,我还没有很好地回答这个问题。 在第 1 节中,我们读到:“虽然每个 Oak 编译单元可以包含多个类或接口,但每个编译单元最多可以有一个类或接口是公共的”。

在侧边栏中,它解释了原因:“编译器尚未强制执行此限制,尽管它是有效导入包所必需的”

这很明显 - 就像大多数事情一样,一旦你知道设计原因 - 编译器将不得不通过所有编译单元(.java 文件)来确定哪些类在哪里,这会使编译变得更慢.

Java 利用此约定通过从类路径开始并扫描子目录中的包层次结构来查找类/接口字节码。 此层次结构的文件系统表示还强制执行一些基本规则。

  1. 同一包中的任何两个 Java 类或接口不能具有相同的名称。 文件名会冲突。
  2. 同一个父包中的任何两个 Java 包不能具有相同的名称。 文件夹路径会发生冲突。
  3. 一个类对同一个包中的所有类具有可见性,而无需修改类路径。

在编译器和程序员之间有一个理解。规则是源代码必须最多有一个公共类,并且该类必须包含主函数。因此,编译器可以在没有任何混淆/限制的情况下访问(公共)该类和将类名命名为类文件。此外,由于该类包含 main(),因此执行类文件将给出正确的流程

它可以在编译(导入指令)期间更有效地查找源文件( .java)和编译( .class)文件,并在执行期间更有效地加载类。 这个想法是:如果你知道一个类的名字,你就知道每个类路径条目应该在哪里找到它。 不需要索引。

我认为这可能是一个可能的原因。 java文件中只能有一个公共类,因为java文件的名称与公共类的名称相同。显然我们不能有两个不同名称的文件。

这就是它的设计方式,我不确定原因是否已记录在案。 但这里有一个很好的理由说明为什么要这样做。 假设我们在一个名为 Y.java 的文件中有两个公共类 Y 和 Z。 现在,假设另一个类 X 正在使用 Z。现在,当我们编译 X 时,编译器首先尝试定位 Z.class,如果找不到,则尝试定位 Z.java,以便它可以自动编译它. 但是,因为我们只有 Y.java,所以无法找到类 Z,因此我们得到一个编译错误。 因此,我们确实需要将它们放在单独的文件中。

带有类的公共修饰符向世界公开,这意味着包之外的任何其他类也可以访问它以解决依赖关系。 现在,这个包含多个类的依赖链被验证了两次——一次是编译时(验证了一级依赖),另一次是执行时(验证了整个依赖链)。

现在假设有一个公共类(A 类),其源文件名与类名不同。 现在,如果其他一些类(比如 B 类)依赖于它,那么在编译 B 类时,java 编译器肯定会检查 A 类的位置,因为该编译器必须通过所有包来搜索 A 类,这很费时间。

现在假设在相同的场景中我们将类 A 的源文件名指定为 A.java ,那么在编译类 B 时,编译器将搜索类 A 并且它只需要找到名称为 A.java 的源文件,所以它不需要遍历所有包(可能包含多个类),它现在只会搜索包含源文件 A.java 的包。

因此,从编译时间、性能角度来看,如果查看一个源文件应该有一个公共类。

A类{


} 公共 B 类{


所以这是正确的,因为 A 不是公共的,编译器不会混淆应该执行哪个类编译器。

公共A类{


} 公共 B 类{


}

所以这是不正确的,因为这里编译器会混淆应该执行哪个类,因为两者都是公共的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM