java - 如何将对象的变量设为final?

标签 java constants 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 做了同样的事情。 。这两个实验都导致相同的结果,编译器不允许我增加最终引用,但允许增加非最终引用,并且在输出中仅非最终变量增加。

在我的第三个实验中,我使用了一个列表,并再次分配了对该列表的非最终引用和最终引用。这里我被允许使用最终和非最终引用来调用 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 的上下文中,不允许您在其中添加或删除元素。是否可以以某种方式标记列表,以便编译器显示错误(或至少某种警告)?

编辑:

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

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

最佳答案

这是一个令人困惑的问题。我会尝试解释一下:

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

  • 在定义最终变量的同一行中分配值。
  • 如果最终变量 B是一个类的属性 A ,然后 B的值可以在 A 的构造函数中赋值类。

但重要的是,当我说分配一个值时,我指的是以下形式的分配: 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 时最后你就是这么做的,说 C不能分配给另一个对象,但该目标对象可以随时更改其状态。

关于java - 如何将对象的变量设为final?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46755736/

相关文章:

java - 解析电子邮件地址以获取域并进行比较

java - 无法使用 HTTPS 使用 AWS S3 Java API 访问 S3 上的存储桶

c++ - 在函数中使用 const int size 参数创建数组会在 Visual Studio C++ 中引发错误 : expression did not evaluate to a constant

java - 具有非最终成员且没有修改器方法的类的线程安全性

java - 在运行时加载驱动程序 jar 文件导致 Perm Gen Space Error

Java线程中断异常

c++ - 这个例子在 Bjarne Stroustrup 的 C++ 编程语言中是如何工作的?

c - 为什么我在尝试将 'char (*c)[6]' 传递给需要 'const char (*c)[6]' 的函数时收到警告?

java - 在java中将对象声明为final

java - 可以添加一个可以转换为现有最终类的新类吗?