如何使Object的变量最终?

时间:2017-10-15 13:48:13

标签: java constants final

我对java中的最终变量有疑问,我写了一个简短的代码来演示这个问题。 java8的语言规范声明:

  

一旦分配了最终变量,它总是包含相同的变量   值。如果最终变量包含对象的引用,那么   可以通过对对象的操作来改变对象的状态,但是   变量将始终引用同一个对象。 Language Specification

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

在我的第三个实验中,我使用了List并再次分配了List的非最终和最终引用。在这里,我被允许使用final和非final参考来调用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

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

编辑:

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

目前包装类的想法似乎是最吸引人的,尽管它对我来说仍然缺少一件事:它不会阻止我或其他人完全改变对象的状态。最终的变量总是有这个“不要触摸”的特性,我在这里寻找。

1 个答案:

答案 0 :(得分:2)

这是一个令人困惑的事情。我会试着解释一下:

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

  • 在您定义最终变量的同一行中指定值。
  • 如果最终变量B是类A的属性,则可以在B类的构造函数中指定A的值。 / LI>

但重要的是,当我说分配了一个值时,我会在表单中引用赋值: final ArrayList<Integet> myArray = new ArrayList<Integer>(Arrays.asList(1,2,3));

现在,变量myArray始终指向该arraylist,并且无法再次以相同的形式分配: myArray = new ArrayList<Integer>(Arrays.asList(4,5,6));会抛出错误。 但话虽如此,您仍然可以在该变量中进行操作。例如,如您所见,您可以添加值:myArray.add(4);

简而言之:当您将变量C标记为final时,您正在这样做,并说C无法分配给其他对象,目标对象可以随时改变他的状态。