当我尝试编译以下代码时,我收到编译错误:
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对象来调用它。
我错过了什么?
答案 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() {
}
}
}