该知识点是自己从书籍中学习的笔记。
不可变类是一个其类实例不能够被修改的简单类。Java平台提供了很多不可变类:String、装箱好的原始数据类型、BigInteger、BigDecimal。使用不可变类是更安全的。为了使一个类成为不可变类,需要以下几个条:
a. 不提供任何修改该对象状态的方法。
b. 确保该类不能够继承,在该类上加final即可。这样可以防止通过子类来修改类的状态。
c. 确保所有属性都是final的。
d. 确保所有的属性都是private的。
e. 对于任何可变组件,确保都是互斥访问的。如果你的类中含有指向对象的引用,请确保该类的客户不能够获取这些指向对象的引用。不能够通过访问器将类中的属性由客户提供的对象引用来初始化或者返回一个对象引用。
不可变对象的优点:
a. 不可变对象可以很好的使用,它只有一个状态,就是在创建的时候;
b. 不可变对象是线程安全的,不要求同步。使用不可变对象可以创建一些经常被访问的对象。比如说可以在类中加上public static final A a = new A(“W”);同时可以将一些经常访问的对象缓存起来。
c. 不可变对象不仅可以被共享,并且其内部结构信息也可以被共享;
d. 不可变对象还为其他对象,无论是可变还是不可变对象,都提供了大量的构件。
不可变类的缺点:
对于每一个值,不可类都要创建一个单独的对象。如果这个值是比较大的话,那么创建成本会增加。比如说,你想要一个一百万位的BigInteger,但是仅仅想修改最低位的值,代码如下:
BigInteger moby = ...;
moby = moby.flipBit(0);//flipBit会返回一个BigInteger的实例,但是仅仅最低位,那么就会浪费很多空间和时间。在这个时候你可以使用BitSet(BitSet是可变对象),因为它中的位是没有顺序的,在同一个时间可以任意修改。
如果使用不可变类,其性能会下降的话,可以使用和它配套的可变类,比如说String有StringBuffer,BigInteger有BitSet。
要使类成为不可变类,除了将class声明为final外,同时可以还可以将class的构造方法声明为private,让子类不能够继承,或者再提供一个静态工厂方法(构造方法都是新生成一个新对象;如果静态工厂方法可以接受一个参数,那么最好是判断其参数的class是否与生成的对象的class是否一致,如getClass())。
总的来说,你应该尽量将类设计成不可变类,虽然在性能上有些缺点。将类设计成不可变类的同时,请提供个与该类功能基本相同的配套的可变类,防止今后要提高性能的时候可以优选它。
对于一些类将其设计成不可变类是不合理的,比如说Thread、TimerTask,这样的过程类。对象的所有初始化工作应该尽量在构造方法中完成,而不应该完成了一部分工作,然后交由其他方法来完成。这样会造成对象的不一致性,除非有足够的理由不得不这样做。