为什么静态最终变量在本地类中被接受? [英] Why static final variables are accepted in local classes?

查看:191
本文介绍了为什么静态最终变量在本地类中被接受?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经google了这个广泛无法使用。我似乎无法围绕这个概念。为什么在本地类中接受静态final字段?如下面的例子:

  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中,变量告别是允许的吗?为什么?我很困惑。为什么允许,但没有静态变量?我理解为什么它不能访问包围作用域的成员,除非它们是编译器时间常量,因为这些变量在函数结束时停止存在,但类可能不会。对?我只是困惑在这。



谢谢!

解决方案

p>

farewell 是一种特殊类型的静态final:其值是一个常数,由 JLS 15.28 。这意味着它不是在那个位置被初始化,这是非静态类(包括本地类)实际上是不允许的,因为 JLS 8.1.3



在8.1.3(注意unless部分)中明确地(以粗体字体):


如果一个内部类声明一个显式或隐式静态成员,除非该成员是一个常量变量(§4.12.4)。


如果你改变这一行,要么删除 final 修饰符,要么使表达式非常量(例如 new String (Bye bye)),那么您将遇到您期望的编译错误:

  Test.java:5:错误:内部类中的非法静态声明EnglishGoodbye 
public static final String farewell = new String(Bye bye);
^
修饰符'static'只允许在常量变量声明中
1错误






多一些:



允许的原因是常量变量是由编译器专门处理的。特别是,它允许内联它们 - 生成的字节码没有告别字段!如果你反编译类( javap -c YourClassName ),你会看到这样的:

  public void sayGoodbyeInEnglish(); 
代码:
0:getstatic#2 //字段java / lang / System.out:Ljava / io / PrintStream;
3:ldc#3 // String Bye
5:invokevirtual#4 //方法java / io / PrintStream.println:(Ljava / lang / String;)V
...

以上对应于此行:

  System.out.println(EnglishGoodbye.farewell); 

这有点令人生畏,但注意到3:行。程序没有加载字段的值 farewell ,它加载常量#3(它注释在字符串Bye bye)(你可以看到维基百科中的字幕代码列表)。



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


I've googled this extensively to no avail. I cannot seem to wrap my head around this concept. Why are static final fields accepted in local classes? Such as the following example below:

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();
    }

In class EnglishGoodbye the variable farewell is allowed? Why? I'm confused. Why is that allowed but no static variable? I understand why it cannot access the members of the enclosing scope unless they are a compiler time constant as those variables cease to exist when the function ends but the class may not. Right? Im just confused on this.

Thanks!

解决方案

It's not, in general.

But farewell is a special kind of static final: one whose value is a constant, as defined by JLS 15.28. That means that it's not being initialized at that location, which is what's actually disallowed in non-static classes (including local classes), as per JLS 8.1.3.

The JLS states this explicitly (and in bold font) in 8.1.3 (note the "unless" part):

It is a compile-time error if an inner class declares a member that is explicitly or implicitly static, unless the member is a constant variable (§4.12.4).

If you change that line to either remove the final modifier or make the expression non-constant (for example, new String("Bye bye")), then you'll get the compilation error you expect:

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


A bit more:

The reason this is allowed is that constant variables are treated specially by the compiler. In particular, it's allowed to inline them -- the resulting bytecode doesn't have the farewell field at all! If you decompile the class (javap -c YourClassName), you'll see something like this:

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
     ...

The above corresponds to this line:

System.out.println(EnglishGoodbye.farewell);

It's a bit daunting, but notice that "3:" line. The program isn't loading the value of the field farewell, it's loading constant #3 (which it note in a comment is the String "Bye bye") (you can see a list of the bytecodes on wikipedia).

Because farewell is a constant variable (and not a "real" static member), and thus can be inlined in the code, it doesn't matter where you define it -- the variable's lifecycle is essentially that of the whole JVM, not any one class or instance, and thus it can be declared anywhere.

这篇关于为什么静态最终变量在本地类中被接受?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆