1、什么是不可变类(immutable class)?
不可变类,顾名思义就是说类的实例是不可被修改的。实例的信息是在创建的时候提供,并且在整个生命周期中都不可改变。
2、有哪些常见的不可变类?
Java的String类和所有基本类型的包装类。
3、什么时候需要将类设计为不可变类?
尽量将一些比较小的对象设计为不可变类(如PhoneNumber和Complex),或者想设计一种有结构的常量的时候,可以考虑设计出一个immutable的类。
4、如何设计不可变类?
a)将成员变量设置为private final:将成员变量设置为final可以很清晰的表明对象状态不可变的意图。
b)不要提供任何会修改对象状态的方法:将成员设置为final后,这个方法明显多余。
c)保证类不会被拓展:这是为了防止子类对该类方法任意的重写,有两种方式来实现:
i:将类设置为final;
ii:将构造方法定义为private,同时提供静态工厂方法;
我们允许利用组合而不是继承的方式来对类进行拓展。
d)如果类包含指向可变类的引用,则get方法返回该引用指向类的一个拷贝。
package immutable;
public class Immutable {
private final int a;
private final ClassA ca;
private Immutable(int a, ClassA ca) {
this.a = a;
this.ca = ca;
}
public static Immutable getImmutable(int a, ClassA oa){return new Immutable(a, oa);
}
public ClassA getOA(){
return oa.clone();
}
public int getA() {
return a;
}
}
5、不可变类的优点
因为immutable类比mutable类更加容易设计,实现和使用。而且不易出错,更加安全。
简单:因为对象一旦生成就他的值就固定了,不变了。从对象状态角度上看,它只有一种状态,没有什么状态变化和迁移。相反,对于一个可以变对象,他的状态变化可就多了,你需要有个状态迁移图才能描述清楚他可能的变化,也就是说他的状态空间可能很大。
线程安全:因为没有修改方法,所以你不用考虑同步的问题,在并发环境中也可以放心的并发read。
节省内存:既然不变对象可以自由的共享。你可以让使用者尽量使用已经存在的实例,而不要重复的创建。你可以定义这些类的一些静态的final实例属性,就像定义一个常量一样。当然你也可以为Immutable 类提供一个静态工厂,由工厂来保证不会创建重复的对象实例。
这样也就节省了内存消耗和垃圾回收负担。如果你有这样的对象,在系统中会被大量的,频繁的,并发的读。不放考虑这种模式。其实String就是一个很好的例子。
很好的构建基石:你应该比较常用到Set和Map,尤其是map的key值,你是否经常需要考虑这些值会不会在你不经意间变了呢?从而使得影响你设定这个set或map的本意。如果用Immutable对象你就不用担心了吧?这样是为什么你总喜欢用String做key值。当然你也可能想尽量避免重写equals和hashCode方法。
6、不可变类的缺点
凡是必然是有利有弊。你知道immutable的对象会因为值的不同而生产新的对象,所以你要谨慎设计你的对象和使用方法。比如String,当你在循环里面连接字符串的时候就不建议你用String的+号,而是用StringBuilder,StringBuilder类用来表示内容可变的字符串,并提供了修改底层字符串的方法。当我们进行字符拼接时,请使用StringBuilder类而非String类,因为前者将比后者快上百倍。这也许也可以知道我们平衡我自己的设计。没准你也可以设计一个immutable类的伙伴(companion)类。
7、总结
如果类不能被做成是不可变的,仍然应该尽可能的限制它的可变性。通过降低对象可以存在的状态数,可以更容易的分析该对象的行为,同时降低出错的可能性。
a)在方法的参数中:如果能加,则推荐加;
b)在方法前:出于设计的原因,我们不允许子类对该方法进行重写;
c)在类前:出于安全或者该类不应该具有子类。final class的方法全为final,但属性却没有。
转载地址:http://www.iteye.com/topic/923644