The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:
在最近的几篇关于不可变性的帖子中,包括《对象应该是不可变的》和《一个不可变对象如何具有状态和行为?》,我对评论中说我对这个概念有误解的数量感到惊讶。大多数评论都表示,不可变对象必须始终以相同的方式行为-这就是不可变性的含义。如果一个方法每次调用时返回不同的结果,那这是什么样的不可变性呢?这不是众所周知的不可变类的行为方式。例如,String
、BigInteger
、Locale
、URI
、URL
、Inet4Address
、UUID
或者包装基本类型的包装类,比如Double
和Integer
。其他评论则质疑了不可变对象作为可变现实世界实体的代表的定义。一个不可变对象如何表示可变实体呢?哼?
我非常惊讶。这篇帖子将澄清不可变对象的定义。首先,这里有一个简单的答案。一个不可变对象如何表示可变实体?比如看看一个不可变类,File
,以及它的方法,比如length()
和delete()
。根据Oracle文档,这个类是不可变的,它的方法每次调用时可能返回不同的值。作为一个完全不可变的File
类对象,它代表了一个可变的现实世界实体,即磁盘上的文件。
在这篇帖子中,我说过“如果一个对象在创建后其状态无法被修改,则该对象是不可变的。”这个定义不是我自己的,而是来自Goetz等人的《Java并发编程实战》第3.4节(顺便说一句,我强烈推荐你阅读这本书)。现在看看这个类(我正在使用jcabi-http来进行HTTP读写):
这个类中的“状态”是什么?没错,this.uri
就是状态。它唯一地标识了这个类的每个对象,并且是不可修改的。因此,该类只创建不可变的对象。而每个对象代表了现实世界中的一个可变实体,一个具有URI的网页。
在这种情况下并不存在矛盾。该类是完全不可变的,而它所代表的网页是可变的。
为什么我与大多数程序员交流后发现,他们认为如果一个底层实体是可变的,那么对象也是可变的?我认为答案很简单——他们认为对象是带有方法的数据结构。这就是为什么从这个角度来看,一个不可变对象是一个永远不会改变的数据结构。
这就是谬误的根源所在——对象不是数据结构。它是一个生活在对象的生活环境(计算机程序)中,代表着现实世界实体的有机体。它确实封装了一些数据,帮助定位现实世界的实体。封装的数据是所代表实体的坐标。对于String
或URL
来说,坐标与实体本身相同,但这只是一个孤立事件,并非普遍规则。
一个不可变对象并不是一个不会改变的数据结构,尽管String
、BigInteger
和URL
看起来像一个。只有当对象不改变所代表的现实世界实体的坐标时,它才是不可变的。在上面的Page
类中,这意味着该类的对象一旦实例化,就永远不会改变this.uri
。无论如何,它始终指向同一个网页。
而对象不能保证该网页的任何行为。该页面是现实世界的一个动态实体,有着自己的生活。我们的对象无法对该页面做出任何承诺。它唯一的承诺是始终忠诚于该页面——永远不会忘记或改变它的坐标。
从概念上讲,不可变性意味着忠诚,仅此而已。
Translated by ChatGPT gpt-3.5-turbo/42 on 2023-12-05 at 21:19