在Java中访问内部类中的静态最终字段

8 java variables class

当我尝试编译以下代码时,我得到编译错误:

unexpected type System.out.println( new Test().C.i );
                                    ^
required: class,package 
found: value
Run Code Online (Sandbox Code Playgroud)
class Test {

    class C {
        static final int i = 0;    
    }

    public static void main(String... z) {
        System.out.println( new Test().C.i  );
    }

}
Run Code Online (Sandbox Code Playgroud)

但是,如果我改变 new Test().C.inew Test().new C().i它编译就好了.

为什么?如果我在C中是静态的,那么我不应该实例化C.我应该只能通过类C而不是C对象来调用它.

我错过了什么?

Voo*_*Voo 5

问题是"." Identifier在Java语法中,期望标识符引用变量而不是类型.

这是在6.5.6.2. Qualified Expression NamesJLS(以及其他地方)中指定的:

如果Q是一个命名类类型的类型名称(§8(Classes)),那么:

如果类类型中没有一个可访问的(§6.6)成员是名为Id的字段,则会发生编译时错误.

否则,如果单个可访问成员字段不是类变量(即,它未声明为静态),则会发生编译时错误.

否则,如果类变量声明为final,则Q.Id表示类变量的值.

表达式Q.Id的类型是捕获转换后的类变量的声明类型(第5.1.10节).

如果Q.Id出现在需要变量而不是值的上下文中,则会发生编译时错误.

否则,Q.Id表示类变量.

表达式Q.Id的类型是捕获转换后的类变量的声明类型(第5.1.10节).

请注意,此子句涵盖枚举常量(第8.9节)的使用,因为它们始终具有相应的最终类变量.

虽然我完全可以理解为什么你会认为它的工作原理 - 我实际上期望它能够正常工作 - 但这并不是什么大问题:因为总有一部分i你可以参考它Test.C.i.如果i是非静态的new Test().new C().i将是访问它的正确方法.

另一种看待它的方法是阅读15.8.主表达式具有主表达式的实际语法(这是我们在这里处理的):它允许ClassInstanceCreationExpression(这就是为什么new Test().new C().i有效)以及FieldAccess(Test.C.i因为"类"以递归方式解析 - 只有最后一个标识符必须然后参考一个字段).


Jar*_*ler -2

我认为之所以new Test().new C().i有效,是因为 Test 类是顶级类,并且被视为static. 如果您要将内部类更改C为静态,那么就new C().i可以了。

但是,您应该以非静态方式访问静态成员。

要访问静态字段,请执行以下操作:

System.out.println(C.i);
Run Code Online (Sandbox Code Playgroud)

编辑:

对于那些说类Test不是静态的人,请参阅此 stackoverflow答案

根据定义,所有顶级类都是静态的。

静态归结为类的实例可以独立存在。或者,相反:如果没有外部类的实例,非静态内部类(=实例内部类)就不能存在。由于顶级类没有外部类,因此它只能是静态的。

因为所有顶级类都是静态的,所以在顶级类定义中使用 static 关键字是没有意义的。


只是为了向您展示以这种方式访问​​静态字段的想法是多么愚蠢,我创建了以下项目:

class Test {

    class C {
        static final int i = 0;
    }

    public static void main(String[] args) {
        // BAD:
        System.out.println(new Test().new C().i);
        // Correct:
        System.out.println(C.i);
    }

}
Run Code Online (Sandbox Code Playgroud)

如果您编译该类并在jd-gui中查看它,您可以看到它是如何编译的:

class Test {

  public static void main(String[] args) {
    void tmp13_10 = new Test(); tmp13_10.getClass(); new C(); System.out.println(0);
    System.out.println(0);
  }

  class C {
    static final int i = 0;

    C() {
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 我问的不是这个。我已经知道了。我问的是学术原因。 (3认同)