可变性与不可变性
在哲学中,有一个被称为“忒修斯之船(Ship of Theseus)”的思想实验。这是西方哲学中最古老的概念之一,大致如下:
英雄忒修斯的著名船只被保存在港口作为博物馆展品。随着岁月流逝,木质部件逐渐腐烂并被替换。一百年后,这艘船的所有木质部件都已被替换。问题是:它还是同一艘船吗?
对于这个问题,有很多种回答方式,可以在维基百科上查到。我们感兴趣的是,这个关于身份的问题同样可以应用到编程中。在编程里,一个与变化和身份直接相关的重要概念就是 (不)可变性(mutability/immutability)。
可变性字面意思是“可被改变的性质”,在编程中,它指的是对象在被创建之后,其状态是否可以改变。
沿着这条思路,我们可以区分可变对象和不可变对象。简单来说:
-
可变对象在创建后可以被修改。
-
不可变对象在创建后不能被修改。
这是可变对象和不可变对象的关键区别。
这在实践中意味着什么?
不可变对象总是代表同一个值:如果你想要一个不同的值,你必须创建一个全新的对象。
而可变对象则更方便,我们可以在不创建新对象的情况下直接修改它们的值。
回到忒修斯之船,如果我们把它看作一个不可变对象,那么答案是:一旦改变了什么,就已经是一个不同的对象。换句话说,即使它还叫“忒修斯之船”,它也不再是原本的那艘船。
相反,如果我们把它看作一个可变对象,那么答案是:它还是同一艘船”。因为这些改变并没有影响它的身份。
在不同的编程语言中,不同类型的对象可能是不可变的。
例如:
-
在 Python 和 Java 中,字符串是不可变的。
-
但在 Java 中,还有
StringBuilder和StringBuffer,它们是可变的。 -
在 Ruby 和 PHP 中,字符串是可变的。
因此,当你在你最喜欢的编程语言中编写程序时,你需要注意哪些对象是可变的,哪些是不可变的。
自定义对象与不可变性
一般来说,自定义类的对象是可变的。
但是,在某些情况下我们希望它们是不可变的:不可变对象是线程安全的,更容易测试,也可能更安全。
-
不可变对象可以在不同线程之间安全共享,而无需额外的保护措施。
-
可变对象的状态很难追踪,因为它们随时可能被任何工作线程修改。
在自定义对象的语境中,我们还可以谈到弱不可变性(weak immutability)和强不可变性(strong immutability)。
-
弱不可变性:对象的一部分字段是不可变的,另一部分是可变的。
-
强不可变性:对象的所有字段都是不可变的。
具体如何让一个自定义类不可变依赖于语言本身,但有一些通用的指导原则:
-
禁止在对象创建后修改字段值,或者禁止字段被重新赋值。
-
可以通过将字段设置为只读或常量来实现。
-
也可以修改设置属性值的方法,让它们在调用时抛出异常。
-
还可以使用访问修饰符:让字段在类外部无法访问。
总结
总而言之,可变对象和不可变对象的区别在于:
-
可变对象:创建后可以修改其状态。
-
不可变对象:创建后不能修改其状态。
不同编程语言有自己的可变/不可变对象划分。
自定义类通常是可变的,但在需要时,可以使用语言特定的工具和技术让它们变成不可变对象。

被折叠的 条评论
为什么被折叠?



