web-dev-qa-db-ja.com

Java:一つのファイルに複数のクラス宣言

Javaでは、1つのファイルに複数のトップレベルクラスを定義できます。ただし、これらのうちの1つがパブリッククラスであることが前提です( JLS§7.6 を参照)。例えば下記を参照してください。

  1. このテクニックにわかりやすい名前はありますか(innernestedanonymousに類似)。

  2. JLSによると、システムはmayこれらの二次クラスを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;
}
221

このテクニックのために私が提案した名前(単一のソースファイルに複数のトップレベルクラスを含む)は "mess"でしょう。真剣に、私はそれが良い考えだとは思わない - 私は代わりにこの状況で入れ子にされた型を使用すると思います。それでも、どのソースファイルに入っているのかを予測するのは簡単です。ただし、このアプローチに正式な用語があるとは思いません。

これが実際に実装の間で変わるかどうかに関して - 私はそれを非常に疑います、しかしもしあなたが最初にそれをしないならば、あなたは決して気にする必要はないでしょう:)

118
Jon Skeet

javacは積極的にこれを禁止していませんが、それがあるファイルと同じ名前でない限り、他のファイルからトップレベルのクラスを参照したくないということを意味するという制限があります。

Foo.JavaとBar.Javaという2つのファイルがあるとします。

Foo.Javaは含まれています:

  • パブリッククラスFoo

Bar.Javaは含まれています:

  • パブリッククラスバー
  • クラスバズ

また、すべてのクラスが同じパッケージに含まれている(そしてファイルが同じディレクトリにある)としましょう。

Foo.JavaがBarではなくBazを参照していて、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はどのソースファイルを調べるべきかをどのように知ることができますか?

代わりにFoo.JavaとBar.Javaを同時にコンパイルするようにjavacに指示した場合、または以前にBar.Javaをコンパイルしたことがある場合でも(javacが見つけられる場所にBaz.classを残して)、このエラーは消えます。しかしこれはあなたのビルドプロセスを非常に信頼できず、薄片状にします。

実際の制限は、「同じ」ファイルと同じ名前でない限り、他のファイルの最上位クラスを参照しないようにするためです。ファイルと同じことは従うのが難しいです。人々は通常、各ファイルにトップレベルのクラスを1つ入れるだけの(もっと厳密ではあるが)もっとわかりやすい規則に従います。これは、クラスをパブリックにするかどうかについて考えが変わった場合にも役立ちます。

時には、誰もが特定の方法で何かをする理由は本当にあります。

122

私はあなたが単にPrivateImplをそれが何であるかと呼んでいると思います:non-public top-level classnon-public top-level interfacesも宣言することができます。

例えば、SOの他の場所では、 非公開の最上位クラスと静的な入れ子クラス

バージョン間の振る舞いの変更に関しては、1.2.2で "完璧に動作した"という何かについての議論がありました。しかし、Sunのフォーラムの1.4での作業を中止しました。 Java Compiler - ファイル内でパブリックではない最上位クラスを宣言できません

22

あなたはこのように望むだけの数のクラスを持つことができます

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

1.このテクニックには、わかりやすい名前がありますか(内側、入れ子、匿名のように)。

マルチクラスのシングルファイルデモ。

2.JLSは、これらの二次クラスは、パッケージの他のコンパイル単位のコードから参照できないという制限をシステムが強制する可能性があると言います。例えば、それらはパッケージプライベートとして扱うことはできません。それは本当にJava実装の間で変わる何かなのでしょうか?

私はそのような制限がないことに気づいていません - すべてのファイルベースのコンパイラはあなたがクラス名と同じ名前ではないファイルの中のソースコードクラスを参照することを許しません。 (もしあなたがマルチクラスファイルをコンパイルし、クラスパスにクラスを置くなら、どんなコンパイラもそれらを見つけるでしょう)

4
Pete Kirkham

Effective Java 2nd edition(Item 13)によると、

「パッケージプライベートの最上位クラス(またはインタフェース)が1つのクラスだけで使用される場合は、それを使用する唯一のクラスの最上位クラスをプライベートのネストクラスにすることを検討してください。パッケージ内のクラスをそれを使用するクラスに変更します。ただし、無償のパブリッククラスのアクセシビリティを、パッケージプライベートの最上位クラスよりも減らすことがはるかに重要です。

ネストされたクラスは、メンバクラスがそれを囲むインスタンスへのアクセスが必要かどうかに基づいて、静的または非静的になります(項目22)。

1
rezzy

はい、できます。外部のパブリッククラスのパブリック静的メンバーを使用すると、次のようになります。

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
1
Alexander Mills