Java 基础系列:不变性
1.1 定义
不可变类(Immutable Objects):当类的实例一经创建,其内容便不可改变,即无法修改其成员变量。
可变类(Mutable Objects):类的实例创建后,可以修改其内容。
Java 中八个基本类型的包装类和 String 类都属于不可变类,而其他的大多数类都属于可变类。
ps: 某个对象在被创建后其状态就不能被修改,那么这个对象就称为不可变对象,不可变对象一定是线程安全的。不可变对象很简单。他们只有一种状态,并且该状态由构造函数来控制。
需要特别注意的是,不可变类的不可变是指该类的实例不可变而非指向该实例的引用的不可变。
1.2 充分条件
当满足以下条件时,对象才是不可变的:
(1)对象创建以后其状态就不能改变;
(2)对象的所有域都是final类型;
(3)对象是正确创造的(在对象创建期间,this引用没有溢出)。
1.3 特征
一个不可变类的定义应当具备以下特征:
所有成员都是 private final 的
不提供对成员的改变方法,例如:setXXXX
确保所有的方法不会被重载。手段有两种:使用final Class(强不可变类),或者将所有类方法加上final(弱不可变类)。
如果某一个类成员不是基本类型(primitive type)或不可变类,必须通过在成员初始化(in)或者getter方法(out)时通过深度拷贝(即复制一个该类的新实例而非引用)方法,来确保类的不可变。
如果有必要,重写hashCode和equals方法,同时应保证两个用equals方法判断为相等的对象,其hashCode也应相等。
1.4 优缺点
1. 优点:效率和安全。
效率(拷贝地址+缓存)
1. 当一个对象是不可变的,那么需要拷贝这个对象的内容时,就不用复制它的本身而只是复制它的地址,复制地址(通常一个指针的大小)只需要很小的内存空间,具有非常高的效率。同时,对于引用该对象的其他变量也不会造成影响。
2. 不变性保证了hashCode 的唯一性,因此可以放心地进行缓存而不必每次重新计算新的哈希码。而哈希码被频繁地使用, 比如在hashMap 等容器中。将hashCode 缓存可以提高以不变类实例为key的容器的性能。
线程安全
在多线程情况下,一个可变对象的值很可能被其他进程改变,这样会造成不可预期的结果,而使用不可变对象就可以避免这种情况同时省去了同步加锁等过程,因此不可变类是线程安全的。
2. 缺点:不可变类的每一次“改变”都会产生新的对象,因此在使用中不可避免的会产生很多垃圾。