我用Google搜索广泛但无济于事。我似乎无法围绕这个概念。为什么本地类接受静态最终字段?如下面的例子:
public void sayGoodbyeInEnglish() {
class EnglishGoodbye {
public static final String farewell = "Bye bye";
public void sayGoodbye() {
System.out.println(farewell);
}
}
System.out.println(EnglishGoodbye.farewell);
EnglishGoodbye myEnglishGoodbye = new EnglishGoodbye();
myEnglishGoodbye.sayGoodbye();
}
在课堂上英语再见允许变量告别?为什么?我很困惑。为什么允许但没有静态变量?我理解为什么它不能访问封闭范围的成员,除非它们是编译器时间常量,因为当函数结束时这些变量不再存在但类可能不存在。对?我只是对此感到困惑。
谢谢!
答案 0 :(得分:4)
总的来说,这不是。
但farewell
是一种特殊的静态最终结果:其值为常量,由JLS 15.28定义。这意味着它没有在那个位置初始化,这是非静态类(包括本地类)实际上不允许的,按照JLS 8.1.3。
JLS在8.1.3中明确说明(并以粗体显示)(注意“除非”部分):
如果内部类声明显式或隐式静态的成员,则该编译时错误,除非该成员是常量变量(§4.12.4)。
如果更改该行以删除final
修饰符或使表达式非常量(例如,new String("Bye bye")
),那么您将得到预期的编译错误:
Test.java:5: error: Illegal static declaration in inner class EnglishGoodbye
public static final String farewell = new String("Bye bye");
^
modifier 'static' is only allowed in constant variable declarations
1 error
再多一点:
允许这样做的原因是编译器特别处理常量变量。特别是,它允许内联它们 - 结果字节码根本没有farewell
字段!如果您反编译该类(javap -c YourClassName
),您将看到如下内容:
public void sayGoodbyeInEnglish();
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String Bye bye
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
...
以上对应于这一行:
System.out.println(EnglishGoodbye.farewell);
这有点令人生畏,但请注意“3:”行。程序没有加载字段farewell
的值,它加载常量#3(它在注释中注释的是字符串“Bye bye”)(你可以看到字节码列表{{3} })。
因为farewell
是一个常量变量(而不是“真正的”静态成员),因此可以在代码中内联,所以在哪里定义它并不重要 - 变量的生命周期基本上是整个JVM,而不是任何一个类或实例,因此它可以在任何地方声明。