Java:在一个文件中有多个类声明

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

  1. 这种技术有一个整齐的名字吗(类似于innernestedanonymous)?

  2. JLS说,系统可以强制这些二级类不能是referred to by code in other compilation units of the package的限制,例如,它们不能被视为包私有。这真的是Java实现之间的变化吗?

例如,PublicClass.java:

package com.example.multiple;


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


class PrivateImpl {
int implementationData;
}
347745 次浏览

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

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

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

假设你有两个文件,Foo.javaBar.java

Foo.java包含:

  • public class Foo

Bar.java包含:

  • public class Bar
  • class Baz

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

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

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

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

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

因为实际的限制,更像是“不要引用来自另一个文件的顶级类,除非它与它所在的文件具有相同的名称,或者你引用的另一个类与该文件中的文件同名”;有点难以遵循,人们通常采用更直接(尽管更严格)的约定,即在每个文件中只放入一个顶级类。如果你改变了一个类是否应该是公共的想法,这也会更好。

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

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

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

我相信你只是简单地称PrivateImplnon-public top-level class。你也可以声明non-public top-level interfaces

例如,SO: 非公共顶级类 vs静态嵌套类上的其他地方

至于不同版本之间的行为变化,有关于在1.2.2中“完美工作”的讨论。但是在sun的论坛:Java编译器-无法在文件中声明非公共顶级类中1.4停止工作。

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

多类单文件演示。

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

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

你想上多少课就可以上多少课

public class Fun {
Fun() {
System.out.println("Fun constructor");
}
void fun() {
System.out.println("Fun mathod");
}
public static void main(String[] args) {
Fun fu = new Fun();
fu.fun();
Fen fe = new Fen();
fe.fen();
Fin fi = new Fin();
fi.fin();
Fon fo = new Fon();
fo.fon();
Fan fa = new Fan();
fa.fan();
fa.run();
}
}


class Fen {
Fen() {
System.out.println("fen construuctor");


}
void fen() {
System.out.println("Fen method");
}
}


class Fin {
void fin() {
System.out.println("Fin method");
}
}


class Fon {
void fon() {
System.out.println("Fon method");
}
}


class Fan {
void fan() {
System.out.println("Fan method");
}
public void run() {
System.out.println("run");
}
}

根据Effective Java第二版(第13项):

"如果包私有顶级类(或接口)仅被 一个类,考虑将顶层类设置为私有嵌套类 唯一使用它的类(第22项)。这就减少了 从其包中的所有类到一个类的可访问性 它使用了它。但更重要的是降低可访问性 一个免费的公共类而不是包私有的顶级类: ... " < / p >

嵌套类可以是静态的,也可以是非静态的,这取决于成员类是否需要访问外围实例(第22项)。

是的,你可以,在一个外部公共类上使用公共静态成员,就像这样:

public class Foo {


public static class FooChild extends Z {
String foo;
}


public static class ZeeChild extends Z {


}


}

和另一个文件引用上述:

public class Bar {


public static void main(String[] args){


Foo.FooChild f = new Foo.FooChild();
System.out.println(f);


}
}

把它们放在同一个文件夹里。编译:

javac folder/*.java

并运行:

 java -cp folder Bar

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

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

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