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

时间:2014-12-28 01:49:35

标签: java class variables

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

unexpected type System.out.println( new Test().C.i );
                                    ^
required: class,package 
found: value

class Test {

    class C {
        static final int i = 0;    
    }

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

}

但是,如果我将new Test().C.i更改为new Test().new C().i,则编译就可以了。

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

我错过了什么?

2 个答案:

答案 0 :(得分:5)

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

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

  

如果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)的使用,因为   这些总是有一个相应的最终类变量。

虽然我完全可以理解为什么你会认为它的工作原理 - 我实际上期望它能够正常工作 - 这不是什么大问题:因为总有一个{{1}你可以通过i来引用它。如果Test.C.i是非静态的,i将是访问它的正确方法。

另一种看待它的方法是阅读15.8. Primary Expressions,它具有主表达式的实际语法(这是我们在这里处理的):它允许new Test().new C().i(这就是为什么{{1} ({1}}(适用于ClassInstanceCreationExpression因为“类”是递归解析的 - 只有最后一个标识符必须引用一个字段)。

答案 1 :(得分:-2)

我认为new Test().new C().i的工作原因是因为类Test是顶级类并被视为static。如果您要将内部班级C更改为静态,则new C().i将起作用。

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

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

System.out.println(C.i);

修改:

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

  

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

     

静态归结为类的实例可以   站在自己的立场上。或者,反过来说:一个非静态的内部类   (=实例内部类)在没有外部实例的情况下不能存在   类。由于顶级类没有外部类,因此不能   不过是静止的。

     

因为所有顶级类都是静态的,所以使用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);
    }

}

如果您编译该类并在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() {
    }
  }
}