不可变对象

对象一旦被创建后,对象所有的状态及属性在其生命周期内不会发生任何变化。

如何创建不可变对象

通常来说,创建不可变类原则有以下几条:

1. 所有成员变量必须是private
2. 最好同时用final修饰(非必须)
3. 不提供能够修改原有对象状态的方法
    ○ 最常见的方式是不提供setter方法
    ○ 如果提供修改方法,需要新创建一个对象,并在新创建的对象上进行修改
4. 通过构造器初始化所有成员变量,引用类型的成员变量必须进行深拷贝(deep copy)
    ○ 若直接赋值其他引用,可能在另一个引用处出现非预期的修改
5. getter方法不能对外泄露this引用以及成员变量的引用
6. 最好不允许类被继承(非必须)

不可变对象并非完全不可变,采用反射可实现改变。但不可变对象存在的意义是为了提醒编程人员该处不希望被更改,而不是单纯的锁死该对象。

final域 final语义--博客

由于重排序的作用,一个线程读取到一个对象引用时,该对象可能尚未初始化完毕,即这些线程可能读取到该对象字段的默认值而不是初始值(通过构造器或者初始化语句指定的值)。

在多线程环境下 final 关键字有其特殊的作用:当一个对象被发布到其他线程的时候,该对象的所有 final 字段(实例变量)都是初始化完毕的,即其他线程读取这些字段的时候所读取到的值都是相应字段的初始值(而不是默认值)。

  1. 在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。
  2. 初次读一个包含final域的对象的应用,与随后初次读这个final域,这两个操作之间不能重排序

而非 final 字段没有这种保障,即这些线程读取该对象的非 final 字段时所读取到的值可能仍然是相应字段的默认值 。对于引用型 final 字段,final 关键字还进一步确保该字段所引用的对象已经初始化完毕,即这些线程读取该字段所引用的对象的各个字段时所读取到的值都是相应字段的初始值 。当一个对象的引用对其他线程可见的时候,这些线程所看到的该对象的 final 字段必然是初始化完毕的。 final 关键字的作用仅是这种有序性的保障,它并不能保障包含final 字段的对象的引用自身对其他线程的可见性。

你可能感兴趣的:(不可变对象)