不可变的类只是实例不能被修改的类。每个实例中包含订单所有信息都必须在创建该实例的时候就提供,并在对象的整个生命周期内固定不变。不可变的类有String、基本类型的包装类、BigInteger和BigDecimal。
要实现不可变的类需要满足一下几点要求:
1、不要提供任何会修改对象状态的方法。(setter方法)
2、不被扩展。用final修饰类或者是私有化构造器提供公有静态工厂方法。
3、使所有的域都是final的。
4、使所有的域都成为私有的。
5、确保对于任何可变组件的互斥访问。
如果类具有指向可变对象的域,则必须确保该类的客户端无法获得指向这些对象的引用。并且,永远不要用客户端提供的对象引用来初始化这样的域,也不要从任何访问方法中返回该对象的引用。在构造器、访问方法和readObject中请使用保护性拷贝。
优点:
简单,线程安全,不要求同步,可自由共享,提供大量构件。
不可变类可以提供一些静态工厂和静态final常量,把频繁被请求的实例缓存起来,从而当现有实例可以符合请求时,不必创建新的实例(降低内存占用和垃圾回收成本):
添加公有的静态工厂来代替公有的构造器
它相比之前的方法:
更灵活,允许使用多个包级私有的实现类。
还可能通过改善静态工厂的对象缓存能力,来改进该类的性能。
静态工厂的名字可以清楚的表明它的功能。
缺点:
对于不同的值都需要一个单独的对象:考虑String的“+”,String s = “a”+“b”会创建三个字符串“a”、“b”、“ab”
构造器应该创建完全初始化的对象,并建立起所有的约束关系。不要在构造器或者静态工厂之外再提供公有的初始化方法,也不要提供重新初始化方法。
实际上,不可变对象所有域都必须是final的,过于严格,为了提高性能可以有所放松,比如String类有一个private int hash;域,当hashCode方法第一次被调用时,把结果放在hash域中,之后调用hashCode方法直接返回hash的值,减少了计算开销,有可能提高性能。因为String被设计成不可变类,所以每次可以确保hashCode计算的结果都是一致的。