最终,不可变对象不是常量?

时间:2017-11-06 12:10:22

标签: java static immutability final

Integerint基元类型(https://docs.oracle.com/javase/7/docs/api/java/lang/Integer.html)的包装器。如果一个对象的状态在构造后不能改变(https://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html),则该对象被认为是不可变的。

我在此理解的是,您只能通过引用完全不同的Integer对象来更改Integer变量的值。

通过声明变量final,我们可以确保以下内容:

  

一旦指定了最终变量,它总是包含相同的值。如果final变量保存对象的引用,则可以通过对象上的操作更改对象的状态,但变量将始终引用同一对象。

再次,通过immutable文档:

  

如果一个对象的状态在构造之后无法改变,则该对象被认为是不可变的。

因此,不允许最终的,不可变的Integer以任何方式更改其值。

如果这是正确的,为什么我们不允许声明public static final Integer变量

following code以不同的方式声明public static final Integer,并且所有这些都返回编译时错误:

import java.util.*;
import java.lang.*;
import java.io.*;

class Ideone
{
    public class Constants {
        public static final String STRING_CONSTANT = "string_constant";
        public static final int INTEGER_CONSTANT = 1; // allowed
        //public static final Integer INTEGER_CONSTANT = 1; // not allowed
        //public static final Integer INTEGER_CONSTANT = new Integer("1"); // not allowed
        //public static final Integer INTEGER_CONSTANT = Integer.valueOf(1); // not allowed
    }
    public static void main (String[] args) throws java.lang.Exception
    {
        System.out.println("STRING_CONSTANT = " + Constants.STRING_CONSTANT);
        System.out.println("INTEGER_CONSTANT = " + Constants.INTEGER_CONSTANT);
    }
}

抛出的异常是:

Main.java:12: error: Illegal static declaration in inner class Ideone.Constants
        public static final Integer INTEGER_CONSTANT = 1;
                                    ^
  modifier 'static' is only allowed in constant variable declarations
1 error

有人可以澄清为什么我们不允许宣布public static final Integer

编辑:我有兴趣了解public static final Integerpublic static final String时不允许public static final int的原因,而不是找到编译的代码。

5 个答案:

答案 0 :(得分:4)

问题不是常量的声明,而是它在内部类中声明的非静态的事实。将类的声明更改为静态并且您很好:

public static class Constants {
    public static final String STRING_CONSTANT = "string_constant";
    public static final int INTEGER_CONSTANT = 1; // allowed
    public static final Integer INTEGER_CONSTANT1 = 1;
    public static final Integer INTEGER_CONSTANT2 = new Integer("1");
    public static final Integer INTEGER_CONSTANT3 = Integer.valueOf(1);
}

答案 1 :(得分:3)

您可以在JLS中找到这背后的原因。

8.1.3. Inner Classes and Enclosing Instances

  

如果内部类声明显式或隐式静态成员,除非成员是常量变量(第4.12.4节),这是编译时错误。

然后,我们可以检查常量变量的定义:

4.12.4. final Variables

  

常量变量是基本类型或类型String的最终变量,使用常量表达式

进行初始化

这就是允许您声明基元或String常量的原因。但是Integer类和其他装箱类不是该异常的一部分,这些实例与任何其他类一样。

来源:Andy Thomas

内联常量

如果我们添加以下内容:

13.1. The Form of a Binary

  

对于作为常量变量(§4.12.4)的字段的引用必须在编译时解析为由常量变量的初始值设定项表示的值V.

我们可以看到那些常量在运行时并不存在,引用在编译时被解析。

代码:

final static int INTEGER_CONSTANT = 1;
int value = INTEGER_CONSTANT;

运行时间“代码”:

int value = 1;

答案 2 :(得分:0)

Java允许public static final Integer,但不允许内部静态内部类。将声明移动到Ideone类或使类Constants为static。 只有当初始化被认为是编译器常量时才能在内部类中声明public static final个字段,这只适用于字符串和主要类型。

public static final String a = new String("ds"); //will not work

答案 3 :(得分:0)

根据JLS,编译时常量表达式是表示基本类型或String的值的表达式。 https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.28

答案 4 :(得分:-1)

看看你的定义。这不是静态最终Integer的问题。但是内部(嵌套)类。内部类是父类的默认属性,并执行需要完成的操作。如果你想让其他类可以看到这个功能,那么使内部类静态,你的代码就可以工作了。但是如果你想使用一些全局配置类声明它不是作为子类。