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

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

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

4

11 に答える 11

57

what I want to know is why java forbids static fields/methods inside inner classes

Because those inner classes are "instance" inner classes. That is, they are like an instance attribute of the enclosing object.

Since they're "instance" classes, it doesn't make any sense to allow static features, for static is meant to work without an instance in the first place.

It's like you try to create a static/instance attribute at the same time.

Take the following example:

class Employee {
    public String name;
}

If you create two instances of employee:

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

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

It is clear why each one has its own value for the property name, right?

The same happens with the inner class; each inner class instance is independent of the other inner class instance.

So if you attempt to create a counter class attribute, there is no way to share that value across two different instances.

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

When you create the instance a and b in the example above, what would be a correct value for the static variable count? It is not possible to determine it, because the existence of the InnerData class depends completely on each of the enclosing objects.

That's why, when the class is declared as static, it doesn't need anymore a living instance, to live itself. Now that there is no dependency, you may freely declare a static attribute.

I think this sounds reiterative but if you think about the differences between instance vs. class attributes, it will make sense.

于 2009-12-23T17:17:28.177 に答える
34

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

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

ところで: のインスタンスを作成することは引き続き可能ですInnerClassstaticこのコンテキストでは、 のインスタンスを囲むことなくそれを行うことができますOuterClass

于 2009-12-23T15:52:29.050 に答える
34

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

8.1.2 内部クラスとそれを囲むインスタンス

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

于 2009-12-23T15:53:42.200 に答える
10

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

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
        }
    }
}
于 2014-12-22T19:32:16.617 に答える
8
  1. クラスの初期化シーケンス は重要な理由です。

インナークラスはエンクロージング/アウタークラスのインスタンスに依存するため、インナークラスの初期化の前にアウタークラスを初期化する必要があります。
これは、JLSがクラスの初期化について述べていることです。 必要なポイントは、次の場合にクラス T が初期化されることです。

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

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

  1. いくつかの基本的なルールに違反します初心者向けのものを避けるために、最後のセクション ( まで ) にスキップできますtwo cases

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

しかし、/ の概念はInner class、外部/囲んでいるクラスに関連付けられます。クラスではなくインスタンスに関連付けられていることに注意してください。インスタンスに関連付けることは、(インスタンス変数の概念から)インスタンス内に存在し、インスタンス間で異なること を明確に意味します。non-static nested classinstance

ここで、静的なものを作成すると、クラスがロードされるときに初期化され、すべてのインスタンス間で共有されることが期待されます。しかし、非静的であるため、内部クラス自体でさえ(今のところ内部クラスのインスタンスについては間違いなく忘れることができます)、外部/囲んでいるクラスのすべてのインスタンスと(少なくとも概念的には)共有されていません。内部クラスのすべてのインスタンス間で共有されます。

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

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

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

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

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++;
        }
    }
}
于 2015-03-24T12:27:55.470 に答える
0

Java 言語設計者自身の言葉で:

ネストされたクラスが最初に Java に導入されて以来、内部にあるネストされたクラス宣言は静的メンバーを宣言することを禁止されてきました...これにより、スコープ内の変数、メソッドなどへの参照を解決および検証する言語のタスクが簡素化されます。

これを禁止する特に壮大な概念的または哲学的理由は決してありませんでした。

言語の単純化は、この制限を維持し続ける理由として不十分であると見なされました。Java 16 でのレコードの導入に伴い、制限を緩和する決定を下しました。

于 2021-12-01T16:44:46.253 に答える
-1

一貫性のためだと思います。技術的な制限はないようですが、内部クラスの静的メンバーに外部からアクセスすることはできません。つまりOuterClass.InnerClass.i、中間ステップが静的ではないためです。

于 2016-06-22T00:29:30.897 に答える