如何使对象的变量最终化?

How to make the variables of an Object final?

我对 java 中的 final 变量有疑问,我写了一段简短的代码来演示这个问题。 java8 的语言规范指出:

Once a final variable has been assigned, it always contains the same value. If a final variable holds a reference to an object, then the state of the object may be changed by operations on the object, but the variable will always refer to the same object. Language Specification

为了进一步调查,我在一个小示例代码中尝试了三件事。我尝试的第一件事是创建一个 Integer 类型的对象并为其分配非最终引用。然后我也为它分配了最终参考。在第二个实验中,我对原始 int 做了同样的事情。这两个实验都导致相同的结果,编译器不允许我递增最终引用,但允许递增非最终引用,并且在输出中只有非最终变量递增。

在我的第三个实验中,我使用了一个 List 并再次分配了对 List 的非最终和最终引用。在这里,我被允许使用最终和非最终参考来调用 add(),并且在两个参考中都更新了大小。

我的测试代码:

public void testFunction () {
    Integer nonFinalInteger = 4;
    final Integer finalInteger = nonFinalInteger;

    nonFinalInteger++;
    //Compiler shows error
    //finalInteger++;

    System.out.println("nonFinal Integer: " + nonFinalInteger);
    System.out.println("final Integer: " + finalInteger + "\n");

    int nonFinalInt = 4;
    final int finalInt = nonFinalInt;

    nonFinalInt++;

    //Compiler shows error
    //finalInt++;

    System.out.println("nonFinal primitive int: " + nonFinalInt);
    System.out.println("final primitive int: " + finalInt + "\n");

    List<String> nonFinalVar = new ArrayList<String>();
    final List<String> finalVar = nonFinalVar;

    finalVar.add("Hello");
    //Compiler does not show error
    nonFinalVar.add("World");

    System.out.println("nonFinal List Size: " + nonFinalVar.size());
    System.out.println("final List Size: " + finalVar.size() + "\n");
}

输出:

nonFinal Integer: 5
final Integer: 4

nonFinal primitive int: 5
final primitive int: 4

nonFinal List Size: 2
final List Size: 2

我现在的问题是:有没有一种方法可以保护对象的状态而不必更改其 class 的代码?假设我们停留在有一个 List 的上下文中,您不应该被允许添加或删除元素。是否可以以某种方式标记列表,以便编译器显示错误(或至少某种警告)?

编辑:

看来我在示例中使用数组引起了一些混淆。我的问题应该涉及任何类型的对象,因此我没有在问题或标签中放入列表。我的意思不是告诉编译器禁止更新引用,我只是想知道是否有一种方法可以隐式地告诉编译器拒绝调用可能改变对象状态的函数。

目前包装器 class 的想法似乎是最吸引人的,尽管它对我来说仍然缺少一件事:它不会阻止我或其他人完全改变对象的状态.最终变量总是具有我在这里寻找的 "do not touch" 特征。

这是一件令人费解的事情。我会试着解释一下:

当你声明一个变量为final时,结果是他的值可以用两种不同的形式赋值:

  • 在定义最终变量的同一行中赋值。
  • 如果最终变量B是classA的属性,那么B的值可以在构造函数中赋值A class.

但重要的是,当我说赋值时,我指的是以下形式的赋值: final ArrayList<Integet> myArray = new ArrayList<Integer>(Arrays.asList(1,2,3));

现在变量 myArray 总是指向那个数组列表并且不能再次以相同的形式赋值: myArray = new ArrayList<Integer>(Arrays.asList(4,5,6)); 会抛出错误。 但话虽如此,您仍然可以对该变量进行操作。例如,如您所见,您可以添加以下值:myArray.add(4);.

简而言之:当您将变量C标记为final时,您就是在这样做,表示无法分配C到另一个对象,但那个目标对象可以随时改变他的状态。