我知道Immutable对象提供了几个优于可变对象的优点,比它们更容易推理而不是可变对象,它们没有随时间变化的复杂状态空间,我们可以自由地传递它们,它们可以创建安全的哈希表键等等。我的问题是不可变对象的缺点是什么?
答案 0 :(得分:6)
引自有效Java :
不可变类的唯一真正缺点是它们需要一个 每个不同值的单独对象。创建这些对象即可 昂贵的,特别是如果它们很大的话。例如,假设你 拥有一百万位BigInteger,你想改变它的低阶 位:
BigInteger moby = ...;
moby = moby.flipBit(0);
上的完整项目flipBit方法 创建一个新的
BigInteger
实例,也就是一百万位长 只有一位与原版不同。这项行动需要时间 和空间与BigInteger
的大小成正比。对比这个java.util.BitSet
。与BigInteger
一样,BitSet
代表任意 长序列,但与BigInteger
不同,BitSet
是可变的。该BitSet
类提供了一种允许您更改状态的方法 在恒定时间内单个百万位实例。
答案 1 :(得分:3)
除了可能的性能缺陷(可能!因为GC和HotSpot优化的复杂性,不可变结构不一定慢) - 一个缺点是现在必须在整个应用程序中穿过状态。对于简单的应用程序或小脚本,以这种方式维护状态的努力可能太高而无法为您提供并发安全性。
例如,想想像Swing这样的GUI框架。完全可以使用不可变结构和一个主要的“不安全”外部循环来编写GUI框架,我想这已经在Haskell中完成了。保持嵌套不可变状态的一些问题可以通过例如透镜来解决。但是管理所有交互(注册侦听器等)可能会非常复杂,因此您可能希望引入新的抽象,例如功能反应或混合反应GUI。
基本上你通过全部不可变来丢失一些OO的封装,当这成为一个问题时,有其他方法,如actor或STM。
答案 2 :(得分:1)
我每天都在与Scala合作。众所周知,不变性具有一定的关键优势。然而,有时在某些情况下允许可变内容更容易。这是一个人为的例子:
var counter = 0
something.map {e =>
...
counter += 1
}
当然,我可以让地图返回带有效负载和计数的元组,或者使用collection.size(如果可用)。但在这种情况下,可变计数器可以说更清楚。一般来说,我更喜欢不变性,但也允许自己做例外。
答案 3 :(得分:1)
要回答这个问题,我会引用Scala编程,第二版,“Scala中的后续步骤”一章,第11项,Lex Spoon,Bill Venners和Martin Odersky:
然而,Scala的观点是,val和var只是工具箱中的两个不同工具,既有用又无本性。 Scala鼓励你倾向于使用vals,但最终可以找到最好的工具。
所以我会说,就像编程语言一样,val和var解决了不同的问题:没有上下文没有“disavantage / avantage”,只有一个问题需要解决,而val / var都解决了不同的问题
希望它有所帮助,即使它没有提供具体的利弊列表!