在Java中,你可以在一个文件中定义多个顶级类,只要其中最多有一个是公共的(参见JLS§7.6)。请看下面的例子。

这种技术是否有一个整齐的名称(类似于内部的、嵌套的、匿名的)? JLS表示,系统可能会强制限制这些二级类不能被包的其他编译单元中的代码引用,例如,它们不能被视为包私有。这真的是Java实现之间的变化吗?

例如,PublicClass.java:

package com.example.multiple;

public class PublicClass {
    PrivateImpl impl = new PrivateImpl();
}

class PrivateImpl {
    int implementationData;
}

当前回答

Javac并没有主动禁止这样做,但它确实有一个限制,这在很大程度上意味着您永远不想从另一个文件引用顶级类,除非它与所在文件具有相同的名称。

假设您有两个文件,Foo.java和Bar.java。

Foo.java包含:

公共类Foo

Bar.java包含:

公共类酒吧 类巴兹

我们还假设所有的类都在同一个包中(文件在同一个目录中)。

如果Foo指向Baz而不是Bar,我们试图编译Foo.java会发生什么?编译失败,出现如下错误:

Foo.java:2: cannot find symbol
symbol  : class Baz
location: class Foo
  private Baz baz;
          ^
1 error

仔细想想,这是有道理的。如果Foo引用Baz,但没有bazz .java(或bazz .class), javac如何知道要查找哪个源文件?

如果您告诉javac同时编译Foo.java和Bar.java,或者您之前编译过Bar.java(将bazz .class留在javac可以找到它的地方),或者即使Foo碰巧引用了Bar而不是Baz,那么这个错误就会消失。然而,这会使您的构建过程感觉非常不可靠和不可靠。

Because the actual limitation, which is more like "don't refer to a top-level class from another file unless it either has the same name as the file it's in or you're also referring to another class that's named the same thing as that file that's also in that file" is kind of hard to follow, people usually go with the much more straightforward (though stricter) convention of just putting one top-level class in each file. This is also better if you ever change your mind about whether a class should be public or not.

新版本的javac也可以在这种情况下使用-Xlint:all生成警告:

auxiliary class Baz in ./Bar.java should not be accessed from outside its own source file

有时候确实有一个很好的理由,为什么每个人都以一种特定的方式做某事。

其他回答

1.这种技术是否有一个整齐的名称(类似于内部的、嵌套的、匿名的)?

多类单文件演示。

2.JLS表示,系统可能会强制限制这些二级类不能被包的其他编译单元中的代码引用,例如,它们不能被视为包私有。这真的是Java实现之间的变化吗?

我不知道有哪个没有这个限制——所有基于文件的编译器都不允许你引用与类名不同的文件中的源代码类。(如果你编译一个多类文件,并把类放在类路径上,那么任何编译器都能找到它们)

我建议将这种技术(包括在一个源文件中包含多个顶级类)命名为“mess”。严肃地说,我不认为这是个好主意——在这种情况下我会使用嵌套类型。然后仍然很容易预测它在哪个源文件中。不过,我不认为这种方法有一个官方术语。

至于这是否会在不同的实现之间发生变化-我非常怀疑,但如果你一开始就避免这样做,你就永远不需要关心:)

不。你不能。但在Scala中这是非常可能的:

class Foo {val bar = "a"}
class Bar {val foo = "b"}

仅供参考,如果你使用Java 11+,这条规则有一个例外:如果你直接运行你的Java文件(没有编译)。在这种模式下,每个文件对单个公共类没有限制。但是,带有main方法的类必须是文件中的第一个类。

Javac并没有主动禁止这样做,但它确实有一个限制,这在很大程度上意味着您永远不想从另一个文件引用顶级类,除非它与所在文件具有相同的名称。

假设您有两个文件,Foo.java和Bar.java。

Foo.java包含:

公共类Foo

Bar.java包含:

公共类酒吧 类巴兹

我们还假设所有的类都在同一个包中(文件在同一个目录中)。

如果Foo指向Baz而不是Bar,我们试图编译Foo.java会发生什么?编译失败,出现如下错误:

Foo.java:2: cannot find symbol
symbol  : class Baz
location: class Foo
  private Baz baz;
          ^
1 error

仔细想想,这是有道理的。如果Foo引用Baz,但没有bazz .java(或bazz .class), javac如何知道要查找哪个源文件?

如果您告诉javac同时编译Foo.java和Bar.java,或者您之前编译过Bar.java(将bazz .class留在javac可以找到它的地方),或者即使Foo碰巧引用了Bar而不是Baz,那么这个错误就会消失。然而,这会使您的构建过程感觉非常不可靠和不可靠。

Because the actual limitation, which is more like "don't refer to a top-level class from another file unless it either has the same name as the file it's in or you're also referring to another class that's named the same thing as that file that's also in that file" is kind of hard to follow, people usually go with the much more straightforward (though stricter) convention of just putting one top-level class in each file. This is also better if you ever change your mind about whether a class should be public or not.

新版本的javac也可以在这种情况下使用-Xlint:all生成警告:

auxiliary class Baz in ./Bar.java should not be accessed from outside its own source file

有时候确实有一个很好的理由,为什么每个人都以一种特定的方式做某事。