Final Vs. Immutability in Java

2025年3月26日 | 阅读 4 分钟

在 Java 中,final不变性是与对象状态和修改相关的两个重要概念。这两个概念都处理对象及其状态的管理方式。在本节中,我们将讨论 Java 中 final 和不变性的区别。

Java final 关键字

Java 中的 final 关键字用作修饰符。它用作类、方法和变量的前缀。

  • Final 变量:一旦我们将一个变量声明为 final,我们就不能改变它的值。这意味着该变量的行为类似于常量
  • Final 方法:声明为 final 的方法不能被子类覆盖,这确保了它们行为的一致性。
  • Final 类:标记为 final 的类不能被继承,这有助于维护其实现,并有助于创建安全或实用类。
  • 初始化:Final 变量必须在声明期间或在构造函数中进行初始化,以确保它们具有确定的值。
  • 性能:final 关键字可以帮助编译器优化代码,从而可能提高性能。
  • 安全性:使用 final 可通过防止对敏感数据或行为的未经授权的修改来增强安全性。

Java 中的不变性

不变性是对象的一个特征。它限制了对象创建后对其状态的任何修改。例如,在 Java 中,String 对象是不可变的。这意味着一旦它们被初始化,它们的内容就不能被更改。

  • 将类声明为 Final:将类标记为 final,以防止它被子类化和潜在地修改。
  • 私有数据成员:将类的私有数据成员声明为私有,以限制直接访问,并确保通过方法进行受控访问。
  • Final 数据成员:将数据成员设为 final,以防止它们在对象构造后被更改。
  • 使用带参数的构造函数:通过带参数的构造函数初始化所有字段,并使用深拷贝来防止通过外部引用进行修改。
  • 在 Getter 方法中返回副本:在 Getter 方法中,返回可变对象的副本(深拷贝),而不是实际的对象引用,以保持不变性。

final 与不变性之间的区别

方面final不可变性
定义确保引用或变量不能被重新分配给另一个对象或值。确保对象的状态在创建后不能被更改。
应用可应用于类、方法和变量。应用于对象以确保其状态保持不变。
变量用法当一个变量是 final 时,它的值在初始化后不能被重新分配。不可变对象的状态一旦设置就不能被改变。
方法用法子类不能覆盖 final 方法。不直接与方法相关;专注于对象状态。
类用法final 类不能被子类化。通过将类设为 final 可以实现不变性,但它并非仅依赖于此。
对对象状态的影响不影响对象的内部状态,只影响引用本身。确保对象的状态在构造后不能改变。
引用与状态引用是固定的,但对象的状态仍然可以使用方法进行修改。引用和对象的状态都是固定的;对象的内部值不能被改变。

让我们通过一个 Java 程序来理解上面讨论的概念。

示例

输出

 
/tmp/LlzHYZ0rSs/Demo.java:17: error: cannot assign a value to the final variable builder
        builder = new StringBuilder("New Content");
        ^
1 error   

解释

  • Final 引用变量:声明一个引用变量为 final 意味着它不能被重新分配给指向另一个对象。但是,它指向的对象仍然可以被修改。
  • 对象修改:在代码中,通过 append() 方法修改了由 builder 引用的 StringBuilder 对象。尽管 StringBuilder 是可变的,但即使引用变量被声明为 final,也可以修改它的内容。
  • 不变性概念:不可变对象在创建后不能改变其状态。由于 StringBuilder 允许追加文本等更改,因此它不符合不可变对象的定义。
  • 编译时错误:尽管 StringBuilder 对象的内容可以被修改,但尝试将 final 变量 builder 重新分配给新的 StringBuilder 实例会导致编译时错误。这是因为 final 禁止重新赋值,但不会影响对象的状态。
  • 重新赋值限制:由于引用变量 builder 是 final 的,因此您不能将新的 StringBuilder 对象分配给它。重新赋值尝试将导致编译时错误,从而确保原始引用不能指向另一个对象。