方法局部类中的 Java 最终静态声明

2022-09-03 05:40:24

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

例如:

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

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

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

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


答案 1

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

来自 Java 语言规范的第 8.1.3 节

8.1.3. 内部类和封闭实例

内部类不能声明静态成员,除非它们是常量变量 (§4.12.4),或者发生编译时错误。

4.12.4开始

基元类型或 String 类型的变量称为常量变量,它是 final 并使用编译时常量表达式 (§15.28) 初始化。

编辑:

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


答案 2

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

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

在整数类中:@Consistent公共整数值Of(int x) {...}

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

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

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


推荐