【问题标题】:Final, immutable objects are not constants? [duplicate]最终的、不可变的对象不是常量吗? [复制]
【发布时间】:2018-04-18 14:30:38
【问题描述】:

Integer 类是 int 原始类型 (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,我们可以确保以下几点:

一旦分配了最终变量,它总是包含相同的值。如果最终变量持有对对象的引用,则对象的状态可能会通过对对象的操作而改变,但变量将始终引用同一个对象。

再一次,通过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 Integer 是不允许的,而 public static final Stringpublic static final int 是不允许的,而不是寻找可以编译的代码。

【问题讨论】:

  • 您的问题并没有指出您要在内部类中声明静态实例的事实。 您可以在该内部类中声明原始常量这一事实确实引起了我的兴趣!
  • 你的类Constants是一个非静态内部类。它不能有静态成员。
  • 感谢您的 cmets。在那种情况下,为什么我们可以声明public static final Stringpublic static final int
  • 我猜编译器正在内联编译时常量,所以你可以避免通常不允许的事情。 Integer 可以是运行时常量,但不是编译时常量,因此它不起作用。

标签: java static immutability final


【解决方案1】:

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

8.1.3. Inner Classes and Enclosing Instances

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

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

4.12.4. final Variables

常量变量是原始类型或字符串类型的最终变量,用常量表达式初始化

这就是为什么你可以声明一个原语或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】:

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

    【讨论】:

      【解决方案3】:

      Java 允许public static final Integer,但不允许在非静态内部类中。将声明移至 Ideone 类或将常量类设为静态。 只有当初始化被认为是编译器常量且仅适用于字符串和原始类型时,您才能在内部类中声明 public static final 字段。

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

      【讨论】:

        【解决方案4】:

        看看你的定义。这不是静态最终整数的问题。但是内部(嵌套)类。内部类默认是父类的属性,做需要做的事情。如果您想让其他类可以看到此功能,请使内部类静态并且您的代码将起作用。但是如果你想使用一些全局配置类,单独声明它而不是子类。

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

          • 感谢您的回答。但是,我不是在寻找代码的解决方案,而是出于不允许 Integer 和 String/int 的原因。
          猜你喜欢
          • 2018-08-23
          • 2011-03-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-12-03
          相关资源
          最近更新 更多