Java中mutable对象和immutable对象
mutable(可变)对象:创建之后也可以修改的对象。开发中创建的大部分类都属于可变类。
immutable(不可变)对象:类的实例一旦创建完成后,就不能改变其成员变量值。
两种对象类型的优缺点
mutable优点:减少数据的拷贝次数,运行效率更高。
mutable缺点:可更改内部数据,使用风险大,且线程不安全。
immutable优点:内部数据的不可变导致其更加安全,可以用作多线程的共享对象而不必考虑同步问题。
immutable缺点:使用时数据大量拷贝,运行效率低。
创建immutable对象的方法
- 类添加final修饰符,保证类不被继承。
如果类可以被继承会破坏类的不可变性机制,只要继承类覆盖父类的方法并且继承类可以改变成员变量值,那么一旦子类以父类的形式出现时,不能保证当前类是否可变。 - 保证所有成员变量必须私有,并且加上final修饰
通过这种方式保证成员变量不可改变。但只做到这一步还不够,因为如果是对象成员变量有可能再外部改变其值。所以第4点弥补这个不足。 - 不提供改变成员变量的方法,包括setter
避免通过其他接口改变成员变量的值,破坏不可变特性。 - 通过构造器初始化所有成员,进行深拷贝(deep copy)。
- 在getter方法中,不要直接返回对象本身,而是克隆对象,并返回对象的拷贝
这种做法也是防止对象外泄,防止通过getter获得内部可变成员对象后对成员变量直接操作,导致成员变量发生改变。
深拷贝(deep copy)
深拷贝:在拷贝引用类型成员变量时,为引用类型的数据成员另辟了一个独立的内存空间,实现真正内容上的拷贝。
深拷贝特点:
- 对于基本数据类型的成员对象,因为基础数据类型是值传递的,所以是直接将属性值赋值给新的对象。基础类型的拷贝,其中一个对象修改该值,不会影响另外一个(和浅拷贝一样)。
- 对于引用类型,比如数组或者类对象,深拷贝会新建一个对象空间,然后拷贝里面的内容,所以它们指向了不同的内存空间。改变其中一个,不会对另外一个也产生影响。
- 对于有多层对象的,每个对象都需要实现 Cloneable 并重写 clone() 方法,进而实现了对象的串行层层拷贝。
- 深拷贝相比于浅拷贝速度较慢并且花销较大。