Real-Time Example for Immutable Class in Java

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

当创建的对象无法更改时,Java 类就被称为具有不可变状态。对象的状态在对象构造完成后永远无法更改。非共享的可变对象始终是线程安全的,这类对象在多线程应用程序中被广泛使用。

实时示例:在二维坐标空间中显示一个点

想象一个图形应用程序,它需要管理二维坐标系中的点。这些点分别由它们的 x 和 y 参数表征。由于点的位置在初始化后不会改变,我们可以将点建模为一个不可变实体。

问题概述

这可能是图形或几何相关应用程序中点的最基本属性,因为一旦确定了点的位置,它就不应改变。例如,如果一个点代表三角形的一个顶点,该点坐标的任何变化都会影响三角形的形状。

因此,通过使用不可变类的概念,您可以仅设置一次点的坐标,之后它们就不会被更改。

拥有不可变类的一些好处如下:

线程安全:创建后状态不会改变的对象本身就是非同步的,因为它们的内容不会改变。

易于使用:其中一个好处是,在使用不可变对象时,多个线程可以共享一个对象,而无需担心有两个或多个线程试图更改对象

可预测的行为:由于不可变对象也不会演变,因此更容易理解它们,尤其是在复杂的世界中。

安全的哈希:因此,我认为不可变对象可以安全地用作基于哈希的集合(如HashMap)中的键,因为它们的哈希码保持不变。

关于 Java 中不可变类需要注意的问题

Final 字段:在建立对象的基本原则时,不可变类的所有字段都应该是 final 的,并且它们只能被赋值一次。

无 Setter 方法:不可变类不应该有 setter 方法来允许在对象创建后为字段设置新值。

构造函数:对于每个对象,构造函数应提供对象字段的完整初始化,并且当字段是对象时,应创建副本。

示例

输出

 
Point p1: Point{x=3, y=4}
Point p2: Point{x=5, y=7}   

注意事项和边缘情况

复杂对象:如果不可变类包含对可变对象的引用,例如数组或集合,则对象的 mutable 状态可能会被损坏;最好的解决方案是在构造函数或访问器中创建对象的深层副本。

性能:从不可变类的家族来看,可能需要实例化一个新对象来适应更改,这在频繁需要更改时是不利的,因为它们会降低性能。

实时应用程序场景

值对象:这是因为,对于日期、货币或坐标等状态不应改变的值对象,不可变类是合适的。

并发:在多线程环境中,更倾向于使用不可修改或“线程安全”的对象,以避免频繁使用计算成本高且实现起来很麻烦的同步。

缓存:由于使用的对象不会改变,因此可以缓存这些对象以反复使用,而无需担心其状态会发生变化。

结论

此示例展示了如何创建一个不可变类的示例。在Java中,存在于二维笛卡尔空间中的 Point 就是一个实时示例。

不可变对象带来了许多好处;它们是线程安全的,易于实现,并且可以安全地用于集合,因此在 Java 编程中是一个有价值的工具,尤其是在多线程或分布式环境中。