一、不可变类简介
不可变类:所谓的不可变类是指这个类的实例一旦创建完成后,就不能改变其成员变量值。如JDK内部自带的很多不可变类:Interger、Long和String等。
可变类:相对于不可变类,可变类创建实例后可以改变其成员变量值,开发中创建的大部分类都属于可变类。
二、不可变类的优点
说完可变类和不可变类的区别,我们需要进一步了解为什么要有不可变类?这样的特性对JAVA来说带来怎样的好处?
- 线程安全
不可变对象是线程安全的,在线程之间可以相互共享,不需要利用特殊机制来保证同步问题,因为对象的值无法改变。可以降低并发错误的可能性,因为不需要用一些锁机制等保证内存一致性问题也减少了同步开销。 - 易于构造、使用和测试
三、不可变类的设计方法
对于设计不可变类,个人总结出以下原则:
1. 类添加final修饰符,保证类不被继承。
如果类可以被继承会破坏类的不可变性机制,只要继承类覆盖父类的方法并且继承类可以改变成员变量值,那么一旦子类以父类的形式出现时,不能保证当前类是否可变。
2. 保证所有成员变量必须私有,并且加上final修饰
通过这种方式保证成员变量不可改变。但只做到这一步还不够,因为如果是对象成员变量有可能再外部改变其值。所以第4点弥补这个不足。
3. 不提供改变成员变量的方法,包括setter
避免通过其他接口改变成员变量的值,破坏不可变特性。
4.通过构造器初始化所有成员,进行深拷贝(deep copy)
5.在getter方法中,不要直接返回对象本身,而是克隆对象,并返回对象的拷贝
这种做法也是防止对象外泄,防止通过getter获得内部可变成员对象后对成员变量直接操作,导致成员变量发生改变。
package com.immutable;
public class ImmutableDemo {
private final int[] myArray;
public ImmutableDemo(int[] array) {
this.myArray = array.clone(); // wrong
}
public int[] get(){
return myArray.clone();
}
}
以上代码就是一个不可变的对象,设计不可变对象的时候可以参考上面五个原则。
jdk的String类就是一个经典的不可变类,
深度克隆的实现方式:
对象实现Cloneable接口并重写Object类中的clone()方法(浅克隆方式);通过重写对象的clone方法,如果对象成员变量也是一个对象,需要递归实现clone()方法
对象实现Serializable接口,通过对象的序列化和反序列化实现克隆(此方法可以实现真正的深度克隆)。