web-dev-qa-db-ja.com

Javaが内部クラスの静的フィールドを禁止するのはなぜですか?

class OuterClass {
 class InnerClass {
  static int i = 100; // compile error
  static void f() { } // compile error
 }
} 

OuterClass.InnerClass.iを使用して静的フィールドにアクセスすることはできませんが、静的なものを記録する場合は、作成されたInnerClassオブジェクトの数は、そのフィールドを静的にするのに役立ちます。 なぜはJava内部クラスの静的フィールド/メソッドを禁止しますか?

編集:私はコンパイラを静的なネストされたクラス(または静的な内部クラス)で満足させる方法を知っていますが、私が知りたいのはJava内部クラス(または通常の誰かがそれについてもっと知っているなら、言語設計と実装の両方の側面からの内部クラス)。

78
Jichao

内部クラスの背後にある考え方は、囲んでいるインスタンスのコンテキストで動作することです。どういうわけか、静的変数と静的メソッドを許可することは、この動機と矛盾しますか?

8.1.2内部クラスと包含インスタンス

内部クラスは、明示的または暗黙的に静的に宣言されていないネストされたクラスです。内部クラスは、静的初期化子(8.7)またはメンバーインターフェイスを宣言できません。内部クラスは、コンパイル時の定数フィールド(§15.28)でない限り、静的メンバーを宣言できません。

26
Gregory Pakosz

私が知りたいのは、なぜJava内部クラス内の静的フィールド/メソッドを禁止する

これらの内部クラスは「インスタンス」内部クラスだからです。つまり、それらは囲んでいるオブジェクトのインスタンス属性のようなものです。

それらは「インスタンス」クラスであるため、static機能を許可することは意味がありません。なぜなら、staticはそもそもインスタンスなしで動作することを意図しているからです。

静的/インスタンス属性を同時に作成しようとするようなものです。

次の例をご覧ください。

class Employee {
    public String name;
}

従業員の2つのインスタンスを作成する場合:

Employee a = new Employee(); 
a.name = "Oscar";

Employee b = new Employee();
b.name = "jcyang";

それぞれがプロパティnameに独自の値を持っている理由は明らかですよね?

同じことが内部クラスでも起こります。各内部クラスインスタンスは、他の内部クラスインスタンスから独立しています。

したがって、counterクラス属性を作成しようとすると、2つの異なるインスタンス間でその値を共有する方法はありません。

class Employee {
    public String name;
    class InnerData {
        static count; // ??? count of which ? a or b? 
     }
}

上記の例でabのインスタンスを作成するとき、静的変数countの正しい値は何ですか? InnerDataクラスの存在は、囲んでいるオブジェクトのそれぞれに完全に依存するため、それを判別することはできません。

そのため、クラスがstaticとして宣言されている場合、それ自体を生きるために生きているインスタンスはもう必要ありません。依存関係がないため、静的属性を自由に宣言できます。

これは反復的に聞こえると思いますが、インスタンス属性とクラス属性の違いを考えると、意味があります。

43
OscarRyz

InnerClassは(staticの)インスタンスに属するため、OuterClassメンバーを持つことはできません。 InnerClassstaticとして宣言してインスタンスからデタッチすると、コードがコンパイルされます。

class OuterClass {
    static class InnerClass {
        static int i = 100; // no compile error
        static void f() { } // no compile error
    }
}

ところで:あなたはまだInnerClassのインスタンスを作成することができます。このコンテキストでstaticを使用すると、OuterClassのインスタンスを囲むことなくそれを実行できます。

33
Asaph

実際、静的フィールドが定数であり、コンパイル時に記述されている場合、静的フィールドを宣言できます。

class OuterClass {
    void foo() {
        class Inner{
            static final int a = 5; // fine
            static final String s = "hello"; // fine
            static final Object o = new Object(); // compile error, because cannot be written during compilation
        }
    }
}
8
vmolchanov

この「制限」に最も適していると思う動機は次のとおりです。内部クラスの静的フィールドの動作を外部オブジェクトのインスタンスフィールドとして実装できます。 だから不要静的フィールド/メソッド。つまり、あるオブジェクトのすべての内部クラスインスタンスがフィールド(またはメソッド)を共有するという動作です。

したがって、すべての内部クラスインスタンスをカウントする場合は、次のようにします。

public class Outer{
    int nofInner; //this will count the inner class 
                  //instances of this (Outer)object
                  //(you know, they "belong" to an object)
    static int totalNofInner; //this will count all 
                              //inner class instances of all Outer objects
    class Inner {
        public Inner(){
            nofInner++;
            totalNofInner++;
        }
    }
}
5
ianos
  1. クラス初期化シーケンスは重大な理由です。

内部クラスは囲む/外部クラスのインスタンスに依存するため、外部クラスは内部クラスの初期化の前に初期化する必要があります。
これはJLSがクラスの初期化について述べている 必要なポイントは、クラスTが初期化される場合です。

  • Tによって宣言された静的フィールドが使用され、フィールドは定数変数ではありません。

したがって、内部クラスに静的フィールドへのアクセスがある場合、内部フィールドの初期化が行われますが、それにより、囲むクラスが初期化されることは保証されません。

  1. 基本的なルールに違反する最後のセクションにスキップして(two casesに)noobを避けることができます

static nestedclassについての1つのこと、一部のnested classstaticの場合、通常のように動作しますクラスはあらゆる方法で、Outerクラスに関連付けられています。

しかし、Inner class/non-staticnested classの概念は、outer /のinstanceに関連付けられますエンクロージングクラス。クラスではなくinstanceに関連付けられていることに注意してください。インスタンスとの関連付けは、(インスタンス変数の概念から)インスタンス内に存在し、インスタンス間で異なることを明確に意味します。

現在、静的なものを作成する場合、クラスがロードされているときに初期化され、すべてのインスタンス間で共有される必要があります。しかし、非静的であるため、内部クラス自体(現時点では内部クラスのインスタンスを忘れることができます)は、外部/囲みクラスのすべてのインスタンス(少なくとも概念的に)、その後、内部クラスの変数が内部クラスのすべてのインスタンス間で共有されることをどのように期待できますか?.

したがって、Javaネストされた静的クラスではなく、内部で静的変数を使用できます。2つのケースがあります。

  • 内部クラスのすべてのインスタンスと共有される場合、context of instance(インスタンス変数)の概念に違反します。それはNOです。
  • すべてのインスタンスと共有されていない場合、静的であるという概念に違反します。再びいいえ。
5
Saif

簡単に言えば、非静的内部クラスは外部クラスのインスタンス変数であり、外部クラスが作成され、実行時に外部クラスオブジェクトが作成され、静的変数がクラスのロード時に作成される場合にのみ作成されます。したがって、非静的内部クラスは実行時のものであるため、静的ではない内部クラスの一部ではありません。

注:内側のクラスは常に外側のクラスの変数のように扱い、他の変数のように静的または非静的にすることができます。

2
Mannu