为什么Joda对象是不可变的?

我已经读过,Java版本小于7,Joda Time对象比Java的内置函数更可靠。 一个引用的原因是Joda对象是不可变的。 为什么这有益? 如果我想更改Joda DateTime对象的年,小时和时区,我需要制作三份副本!

如果我想更改Joda DateTime对象的年,小时和时区,我需要制作三份副本!

确实是的。 或者,您可以使用旧对象中的所有字段创建一个新对象,当然。

这是一件非常好的事情 – 因为这意味着当你想要依赖一个不改变的物体时,它就不会。 考虑这个伪代码:

 private static final Instant EARLIEST_ALLOWED_ARTICLE = ...; private Instant creationTimestamp; public Article(Instant creationTimestamp, ...) { if (creationTimestamp.isBefore(EARLIEST_ALLOWED_ARTICLE)) { throw new IllegalArgumetnException(...); } this.creationTimestamp = creationTimestamp; ... } 

那没关系,因为Instant是不可改变的。 如果它是可变的,那么构造函数中的validation将毫无价值 – 除非你在那时创建了一个防御性副本。

根据我的经验,您希望传递引用并知道值的变化不会超过您希望实际更改现有对象的变化,因此不变性会导致更少的错误(使用可变对象可以忘记复制,以及任何validation都是无用的)并且制作的副本更少。

基本上,它允许您在本地推理您的代码而无需复制您接受和存储的所有内容,或返回其他代码。 当只有你的代码可以改变对象的状态时,弄清楚随着时间的推移会发生什么变得更加简单。

Joda Time实际上有些失败,因为它有可变类型不可变类型 – 如果你只是编程到接口 (例如ReadableInstant ),那么你就不会得到这些保证。 这就是为什么在Noda Time我把所有类型都变成了真正不可改变的原因。

出于兴趣,你想要String是可变的吗? 如果没有,请尝试考虑两种方案之间是否存在实际差异。

最简单的答案是,一旦创建了一个对象,就会知道它无法改变。 这意味着您不会遇到数据以意外方式发生变化的情况(在代码的其他部分或可能不同的线程中)。

这使得对象的行为更加可预测和可靠。

可能有很多原因,但一个好的原因是哈希。 不可变对象可用于散列数据结构(例如HashSet,HashMaps中的键等),因为它们的散列码和“相等”语义不会改变。 可变对象不适合散列,因为突变可能会改变其哈希码或相等。

通过使Joda日期不可变,它们现在可以用于散列数据结构。

我认为这是由于这个原因:

想象一下,你有一个java.util.Date-object,它在多个类中使用。 我正在一个class级进行开发,另一个class级。 然后,我决定我需要预测未来,但我没有创建一个新的Date对象,而是采用我已经拥有的那个,你认为代表某个时间点的那个,并且我添加了三个小时。 现在,您的代码可能会在运行时遇到严重问题。 使用不可变对象可以避免这一切,因为你不能改变它的状态,你不能把它搞砸给其他任何人。

不幸的是,DateTime的实现不是不可变的[1],因为没有使用final

https://github.com/JodaOrg/joda-time/blob/master/src/main/java/org/joda/time/DateTime.java

[1]术语“不可变”通常被理解为“线程安全不可变”。