方法本地类中的Java final静态声明

chr*_*ood 16 java final static-members inner-classes

在方法中声明本地内部类时,为什么包含最终的静态字符串或整数是合法的,但包含其他对象却不合法?

例如:

class Outer {
void aMethod() {
    class Inner {
        final static String name = "compiles";
        final static int ctr = 10; // compiles
        final static Integer intThree = Integer.valueOf(3); // does not compile!
        final static obj objConst = new Object(); // does not compile!
    }

    Inner inner = new Inner();
}
}
Run Code Online (Sandbox Code Playgroud)

当我编译它时,我得到以下内容:

InnerExample.java:6: inner classes cannot have static declarations
        final static Integer outer = Integer.valueOf(3);
                             ^
InnerExample.java:7: inner classes cannot have static declarations
        final static Object objConst = new Object();
                            ^
Run Code Online (Sandbox Code Playgroud)

为什么区别?是因为String是不可变的吗?如果是这样,Integer.valueOf()也不会有效吗?

And*_*mas 17

这是因为前两个静态成员被分配给基本类型或类型String的编译时常量.

Java语言规范,第8.1.3节:

8.1.3.内部类和封闭实例

内部类可能不会声明静态成员,除非它们是常量变量(第4.12.4节),否则会发生编译时错误.

4.12.4开始:

原始类型或类型String的变量是final,并使用编译时常量表达式(第15.28节)初始化,称为常量变量.

编辑:

起初我发现这令人惊讶.考虑到这一点,这个限制的一个优点是无需担心内部类的静态成员何时被初始化.您可以在其包含的类中移动内部类,而不必担心其静态成员的值将被更改.


小智 5

更多关于以前的答案.分配的值必须由编译器证明它是常量.Java编译器知道基类型(int,float等)和java.lang.String类的语义,但不知道其他类的语义.这可以理解前两个例子的不变性.

编译器不理解Integer.valueOf(3)也(有效地)是一个常量(实际上不是常量,但总是相同)值,即使知道Integer类如何工作的人知道这一点.编译器将其视为可以更改的Integer.valueOf(x).如果Java提供了一个注释,例如@interface Consistent,它会将方法行为声明为任何给定参数的稳定性,例如:

在Integer类中:@Consistent public Integer valueOf(int x){...}

final static Integer intThree = Integer.valueOf(3); //现在编译!

这表明该方法在给定相同参数值的每次调用时返回相同或相等的对象.由于参数是常量表达式,因此编译器可以推断出结果在所有用法中都是相同/相等的,因此可以将其视为常量.在这种情况下,Integer返回相同的对象,但它可以为更大的输入值返回一个不同(但相等)的对象(即,它将值缓存在0附近).

请注意,"new"始终返回不同的对象.对于新的Object(),它始终是一个不等于任何其他对象的对象.