为什么静态字段(不是final)在java中的内部类中受到限制

时间:2012-10-04 12:25:04

标签: java inner-classes static-members

  

可能重复:
  Why does Java prohibit static fields in inner classes?

我正在查看规范并得到内部类中的静态成员不可能是最终编译时间常量。

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
}

我从Why can we have static final members but cant have static method in an inner class?得到它可以从其所有者类继承静态成员。但为什么不应该呢? OOP的主要伤害是什么?

5 个答案:

答案 0 :(得分:12)

您的班级myInnerClassTest未声明为静态。那么这对于它有一个静态字段究竟意味着什么呢?

是不是

  • 对于所有实例,无论封闭实例是什么?
  • 对于具有相同封闭实例的此内部类的所有实例都一样吗?
乍一看,大多数程序员可能认为这是第一种情况,而(非静态)内部类的封装逻辑应该可能导致第二种选择。无论是哪种情况(或两者都有不同的修饰语)都需要static的新定义,这可能不是必要的。在任何一种情况下,程序员都会对确切的含义感到困惑。

来自the specification

  

内部类是一个非显式或隐式的嵌套类   声明静态。

     

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

     

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

     

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

答案 1 :(得分:10)

根据JLS: -

  

8.1.3内部类和附件实例

     

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

     

任何局部变量,形式方法参数或异常处理程序   必须声明已使用但未在内部类中声明的参数   最后。使用但未在内部类中声明的任何局部变量   必须在内部类的主体之前明确地分配(§16)。

除了这两件事,我觉得很重要..还有很多你可以从那里得到它......关于inner classes,{{1}有一个很大的解释}和anonymous inner classes ..

更新说明: -

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

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

注意: - non-static 不是编译时间常数 ..所以,你不能将它们放在你的内心类

另一方面,如果您的内部类是static final Object = null,这实际上是一个嵌套类,那么您可以将您的字段声明为静态,因为它们仍将与该类关联,因此您甚至可以访问它们在实例化之前封闭类..

我希望这是有道理的。

更新2 : -

static

在上面的代码中,public class A { class B { static int x = 0; } } 对于B类的每个实例都是通用的。 此外,static variable x的每个实例都有自己的class A副本(因为 JVM 必须每次加载B类一个{{ 1}}已创建)..

因此,class B的每个实例之间都不能共享instance of A,除非它是编译时常量...(为了使更直接的前进: - 如果你看到B是外类,你可以做 - static variable x但是对于A类的每个实例,B类本身都是不同的。因此,对于A类的每个实例, class A都是不同的。 ..因此,静态变量B.x实际上并未在 A类的不同实例之间共享。对于静态变量没有意义。)

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

答案 2 :(得分:1)

所有限制均记录在案 JLS #8.1.3. Inner Classes and Enclosing Instances

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

innerclass

非静态内部类是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中记录

答案 3 :(得分:0)

因为内部类与顶级类密切相关,所以必须有一个外部类的实例来创建内部通道

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

因此,它与实例相关联,而不是与类相关联。

答案 4 :(得分:-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”。