20

可能重复:
为什么 Java 禁止内部类中的静态字段?

我正在阅读规范,并了解到内部类中不可能有静态成员,这不是最终的编译时间常量。

class HasStatic {
    static int j = 100;
}
class myInnerClassTest {
    class Inner extends HasStatic {
        static final int x = 3;  // OK: compile-time constant
        static int y = 4;  // Compile-time error: an inner class
    }
    static class NestedButNotInner{
        static int z = 5;    // OK: not an inner class
    }
    interface NeverInner {}   // Interfaces are never inner
}

而我从为什么我们可以有静态最终成员但不能在内部类中有静态方法?它可以从其所有者类继承静态成员。但为什么不应该呢?它伤害了 OOP 的什么校长?

4

5 回答 5

12

您的类myInnerClassTest未声明为静态的。那么拥有一个静态字段究竟意味着什么呢?

可不可能是

  • 无论封闭实例如何,所有实例都相同?
  • 这个内部类的所有实例都具有相同的封闭实例吗?

乍一看,大多数程序员可能会认为这是第一种情况,而(非静态)内部类的封装逻辑可能会导致第二种选择。任何一种情况(或两者都具有不同的修饰符)都需要一个新的定义,static这可能被认为是不必要的。在任何一种情况下,程序员都会对确切的含义感到困惑。

规范

内部类是没有显式或隐式声明为静态的嵌套类。

内部类包括本地(§14.3)、匿名(§15.9.5)和非静态成员类(§8.5)。

内部类不能声明静态初始化器(第 8.7 节)或成员接口,否则会发生编译时错误。

内部类不能声明静态成员,除非它们是常量变量(第 4.12.4 节),或者发生编译时错误。

于 2012-10-04T12:34:39.933 回答
10

根据JLS:-

8.1.3 内部类和封闭实例

内部类是没有显式或隐式声明为静态的嵌套类。内部类不能声明静态初始化器(第 8.7 节)或成员接口。内部类不能声明静态成员,除非它们是编译时常量字段(第 15.28 节)。

任何使用但未在内部类中声明的局部变量、形式方法参数或异常处理程序参数都必须声明为 final。任何在内部类中使用但未声明的局部变量必须在内部类的主体之前明确分配(第 16 节)。

除了这两件事inner classes,我发现它们很重要。你可以从那里得到更多的东西。关于,anonymous inner classesnested classes..有很多解释。

更新说明:-

考虑一下。静态块在类初始化期间执行,如果没有封闭类的实例,您无法初始化非静态内部类,这就是原因。

内部类与instance封闭类的相关联。它们就像封闭类的其他实例属性一样。现在,static在上下文中嵌入字段是没有意义的non-static。但是,如果将它们声明为编译时间常量他们将被允许。

注意: -static final Object = null 不是编译时常量..所以,你不能把它们放在你的内部类中

另一方面,如果您的内部类staticbe ,实际上是一个嵌套类,那么您可以将您的字段声明为静态,因为它们仍将与该类关联,因此您甚至可以在将类包含在实例化之前访问它们。

我希望这是有道理的..

更新 2: -

public class A {
   class B {
        static int x = 0;
   }
}

在上面的代码中,static variable xB 类的每个实例都是通用的。此外, , 的每个实例class A都有自己的副本class B(因为每次创建an时JVM都必须加载 B 类)。instance of A

因此,除非它是编译时常量,否则static variable x不可能在 的每个实例之间共享class A。(为了使其更直接:-您可以这样做-B.x如果您将 B 视为外部类..但是 B 类本身不同A 类的每个实例。因此, B.xA 类的每个实例都会有所不同。因此,静态变量x实际上并未在A 类的不同实例之间共享。对静态变量没有意义。)

我希望现在,这是有道理的..

于 2012-10-04T12:38:19.010 回答
1

所有限制都记录在 JLS #8.1.3 中。内部类和封闭实例

因为静态声明与 Class 相关联,如果您在内部类中声明它,它将与实例而不是类相关联。

内部阶级

非静态内部类是 Object 的成员。并且对于成员初始化仅在创建对象实例时发生。如果允许静态变量,那么初始化将在创建实例之前发生。

这就是为什么有单独的non-staticstatic内部的类。

您总是需要外部类实例来访问内部类,Outer.Inner唯一的例外是static inner class没有适用于非静态内部类的约束。

static class Inner {
    static final int x = 3; // OK: compile-time constant
    static int y = 4;// OK
    static class NestedButNotInner {// OK

    }

    interface NeverInner {// OK
    };
}

然而,常量是允许的,它记录在 JLS

于 2012-10-04T12:37:39.627 回答
0

因为内部类与顶级类密切相关,所以您必须拥有外部类的实例才能创建内部通过

Outer o = new Outer();
Inner i = o.new Inner();

因此,这与一个实例而不是一个类相关联。

于 2012-10-04T12:51:19.807 回答
-1

如您所知,内部类可以从其所有者类继承静态成员。

class HasStatic {
    static int j = 100;
}
class myInnerClassTest {
    class Inner extends HasStatic {
    }      
    public static void main(String[] args){
        System.out.println(Inner.j);
    }
}

它打印“100”。

于 2012-10-04T12:55:19.237 回答