解读:在设计一个类的时候尽可能使类成为一个不可变类,如果不能设计为不可变类,也要尽可能使可变性最小。
- 怎么理解不可变类?
不可变类是指其实例无法修改。也就是说,不可变类的实例所包含的信息是在创建的时候就已经初始化好了,后续不能修改,在整个对象的生命周期内是固定不变的。例如String、所有基本类型的包装类、BigDecimal等都是不可变类。更深入一点理解就是,在实例化一个类的时候,在堆上开辟的一块空间所包含的信息,后续无法再修改该空间上的信息了。
不可变类需要遵循的5点:
1、不要提供修改任何会修改对象状态的方法。简单理解,就是类的成员变量不能提供set方法。
2、保证类不会被扩展。也就是类不能继承,类声明为final(或者私有化构造函数,提供静态工厂方法)(具体参见要点1))。
3、使所有的域都成为final。final的成员变量只能在构造的时候给值,后续无法再修改该值,也不能给它提供set方法。这一点要求过于严格,有时候类内部本身自己需要的一个可变的成员做相关的处理。
4、使所有的域都成为私有的。私有即代码不能直接获取到该域,当然关于这一点其实只要域设置成final了,并且域是基本类型的值或者指向的是不可变对象的引用,及时是公有的也没有问题,不过作者还是建议把域设置成私有的(这一点13点已经说过了)。
5、确保对于任何可变组件的互斥访问。这一点的意思就是说类似于要点13说过的,虽然成员变量声明的是final但是它的类型是可变得类型,依然是可以修改的。因此这种情况就是不要直接提供get方法能够获取到该变量的引用。
- 不可变对象的特性:
1、不可变对象简单。这里说的简单是指,这个类的实例在创建的时候状态就是它一直的状态,不可能再发生变化,所以你不用担心它会发生你无法预测的变化。
2、不可变对象本质上是线程安全。不能修改必定是线程安全的。
3、不可变对象可以被自由地共享。可以结合String的常量池理解,就是可以把频繁使用到的鄂值缓存起来作为重用的实例。
4、不可变对象为其他对象提供大量的构件。就是上面要遵循的第5点的意思。
5、唯一缺点:每个不同的值都需要一个单独的对象。也就是每一个值都需要新开辟一块堆空间去保存。这也就是String为什么不建议频繁修改的原因。关于这个缺点的解决方法是对每一个不可变类提供它的可变配套类,如StringBuilder、StringBuffer。
文中最后总结了一句话:对于类能设计成不可变类尽量设计为不可变类,构造器(包括静态工厂方式)应该创建完全初始化的对象,不要在构造器(包括静态工厂方式)之外再提供公有的初始化方法。