为什么Java禁止内部类中的静态字段?

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

虽然用OuterClass.InnerClass.i访问静态字段是不可能的,但是如果我想logging一些应该是静态的东西,例如创build的InnerClass对象的数量,那么将这个字段设置为静态是有帮助的。 那么为什么 Java禁止内部类中的静态字段/方法呢?

编辑:我知道如何使编译器满意静态嵌套类(或静态内部类),但我想知道的是为什么Java禁止内部类(或普通的内部类)内的静态字段/方法从语言devise和实施方面,如果有人知道更多关于它。

谢谢。

内部类的背后的想法是在封闭的实例的上下文中操作。 不知何故,允许静态variables和方法与这个动机相矛盾?

8.1.2内部类和包含实例

一个内部类是一个嵌套类,不是明确或隐式地声明为静态的。 内部类可能不声明静态初始值设定项(§8.7)或成员接口。 内部类可能不会声明静态成员,除非它们是编译时常量字段(第15.28节)。

InnerClass不能有static成员,因为它属于一个( OuterClass )实例。 如果你声明InnerClassstatic ,将它从实例中分离出来,你的代码将被编译。

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

顺便说一句:你仍然可以创buildInnerClass实例。 在这种情况下static允许发生没有封闭的OuterClass实例。

我想知道的是为什么java禁止内部类中的静态字段/方法

因为这些内部类是“实例”内部类。 也就是说,它们就像封闭对象的一个​​实例属性。

由于它们是“实例”类,因此staticfunction是没有任何意义的,因为static是为了在没有实例的情况下工作。

这就像你试图同时创build一个静态/实例属性。

以下面的例子:

 class Employee { public String name; } 

如果您创build两个员工的实例:

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

很明显,为什么每个人都有自己的财产name的价值,对吗?

内部阶层也是如此。 每个内部类实例独立于另一个内部类实例。

因此,如果您尝试创buildcounter类属性,则无法跨两个不同的实例共享该值。

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

当在上面的例子中创build实例ab时,静态variablescount值是什么? 这是不可能的,因为InnerData类的存在完全取决于每个封闭的对象。

这就是为什么当这个类声明为static ,它不再需要一个活的实例来活着。 既然没有依赖关系,你可以自由地声明一个静态属性。

我认为这听起来有点反复,但是如果你考虑实例与类属性之间的差异,这将是有道理的。

实际上,你可以声明静态字段,如果它们是常量,并在编译时写入。

 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 } } } 

下面是我最适合这个“限制”的动机:你可以实现内部类的静态字段的行为作为外部对象的实例字段; 所以你不需要静态字段/方法 。 我的意思是,一些对象的所有内部类实例共享一个字段(或方法)。

所以,假设你想要统计所有的内部类实例,你可以这样做:

 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++; } } } 
  1. 类的初始化顺序是一个关键的原因。

由于内部类依赖于包含/ Outer类的实例,所以需要在Inner类的初始化之前初始化Outer类。
这是JLS关于类初始化的说法。 我们需要的是,如果T类将被初始化

  • 使用由T声明的静态字段,该字段不是常量variables。

所以如果内部类有一个静态字段访问会导致内部类的初始化,但不能确保封闭类被初始化。

  1. 这违反了一些基本规则你可以跳到最后一节( two cases ),以避免noob的东西

关于static nested class一件事情是,当某个nested classstatic时候,它将以各种方式像普通类一样运行,并且与外部类相关联。

但是Inner class / non-static nested class的概念是与外部/封闭类的instance关联的。 请注意与实例不相关的类。 现在,与实例关联清楚地表示( 从实例variables的概念 )它将存在于一个实例内,并且在实例之间将会不同。

现在,当我们做一些静态的东西的时候,我们期望在类加载的时候它会被初始化,并且应该被所有的实例共享。 但是对于非静态的,甚至内部类本身( 你现在可以肯定忘记内部类的实例 )并不与外部/封闭类的所有实例共享( 至less在概念上 ),那么我们怎么能期望一些variables内部类的所有实例将被共享。

所以如果Java允许我们在静态嵌套类中使用静态variables。 会有两种情况

  • 如果它与内部类的所有实例共享,将违反context of instance (实例variables) context of instance的概念。 那是不行的
  • 如果不与所有实例共享,将违反静态的概念。 再次没有。

我想这是为了一致。 虽然看起来没有任何技术限制,但是你不能从外部访问内部类的静态成员,即OuterClass.InnerClass.i因为中间步骤不是静态的。