Java:一个文件中的多个类声明

时间:2010-02-25 18:45:29

标签: java class

在Java中,您可以在单个文件中定义多个顶级类,前提是其中一个是公共的(请参阅JLS §7.6)。例如,见下文。

  1. 此技术是否有一个整洁的名称(类似于innernestedanonymous)?

  2. JLS表示系统可能强制执行这些辅助类不能referred to by code in other compilation units of the package的限制,例如,它们不能被视为包私有。这真的在Java实现之间发生了变化吗?

  3. ,例如,PublicClass.java:

    package com.example.multiple;
    
    public class PublicClass {
        PrivateImpl impl = new PrivateImpl();
    }
    
    class PrivateImpl {
        int implementationData;
    }
    

9 个答案:

答案 0 :(得分:122)

javac没有主动禁止这一点,但它确实有一个限制,几乎意味着你永远不想从另一个文件引用顶级类,除非它与它所在的文件具有相同的名称。

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

Foo.java包含:

  • 公共课Foo

Bar.java包含:

  • public class Bar
  • class Baz

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

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

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

如果您考虑一下,这是有道理的。如果Foo.java引用了Baz,但是没有Baz.java(或Baz.class),那么javac如何知道要查找的源文件呢?

如果您告诉javac同时编译Foo.java和Bar.java,或者即使您之前编译过Bar.java(保留了javac可以找到它的Baz.class),那么这个错误就会消失。但是,这会使您的构建过程感觉非常不可靠和不稳定。

因为实际的限制,更像是“不要从另一个文件引用顶级类,除非它与它所在的文件具有相同的名称,或者你也指的是同一个类中的一个类与文件命名相同的文件“有点难以理解,人们通常会采用更简单(尽管更严格)的惯例,即在每个文件中放置一个顶级类。如果您改变主意是否应该公开课程,这也会更好。

有时候每个人都以某种特定的方式做某事真的有充分的理由。

答案 1 :(得分:117)

我对这种技术的建议名称(包括单个源文件中的多个顶级类)将是“混乱”。说真的,我认为这不是一个好主意 - 在这种情况下我会使用嵌套类型。然后,它仍然很容易预测它所在的源文件。我不相信这种方法的官方术语。

至于这实际上是否在实现之间发生了变化 - 我非常怀疑它,但如果你首先避免这样做,你将永远不需要关心:)

答案 2 :(得分:22)

我相信你只需致电PrivateImpl它是什么:non-public top-level class。您也可以声明non-public top-level interfaces

例如,SO上的其他地方:Non-public top-level class vs static nested class

至于版本之间的行为变化,有关于1.2.2中“完美运行”的内容的讨论。但在太阳的论坛中停止了工作:Java Compiler - unable to declare a non public top level classes in a file

答案 3 :(得分:6)

你可以拥有任意数量的课程

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");
    }
}

答案 4 :(得分:4)

  

1.这个技术有一个整洁的名称(类似于内部,嵌套,匿名)?

多级单文件演示。

  

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

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

答案 5 :(得分:1)

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

  

“如果仅使用包私有顶级类(或接口)   一个类,考虑使顶级类成为私有嵌套类   使用它的唯一类(第22项)。这减少了它   从其包中的所有类到一个类的可访问性   使用它。但是减少可访问性更为重要   一个无偿的公共课程而不是一个包私有的顶级课程:   ......“

根据成员类是否需要访问封闭实例(第22项),嵌套类可以是静态的或非静态的。

答案 6 :(得分:1)

是的,可以在外部公共类上使用公共静态成员,如下所示:

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

答案 7 :(得分:0)

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

答案 8 :(得分:-2)

不。你不能但是在Scala中很有可能:

(?:USD ?)?(?:\d{1,3})(?:,\d{3})*(?:[.,]\d{1,2})?