小编典典

为什么局部类会接受静态最终变量?

java

我已经在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();
    }

在EnglishGoodbye课堂上,允许告别可变吗?为什么?我很困惑。为什么允许但没有静态变量?我知道为什么它不能访问封闭范围的成员,除非它们是一个编译器时间常数,因为当函数结束时这些变量不再存在,但类可能不存在。对?我只是对此感到困惑。

谢谢!


阅读 318

收藏
2020-11-26

共1个答案

小编典典

一般而言,不是。

但是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”)(您可以在Wikipedia上看到字节码的列表)。

因为farewell是一个常量变量(而不是“真正的”静态成员),因此可以内联到代码中,所以在哪里定义它都无所谓-
变量的生命周期本质上是整个JVM的生命周期,而不是任何一个类或实例,因此可以在任何地方声明。

2020-11-26