1、不可变类
(1)不可变类是指这个类的实例一旦创建完成后,就不能改变其成员变量值,也就是不能改变对象的状态。
(2)Java 中八个基本类型的包装类和 String 类都属于不可变类,而其他的大多数类都属于可变类。
(3)不可变对象是线程安全的。
2、如何设计不可变类?
(1)类声明为final,不可以被继承。
(2)所有成员变量定义为私有和final(private final)。
(3)不提供改变成员变量的方法。
(4)通过构造器初始化成员,若构造器传入引用数据类型需要进行深拷贝。
public final class ImmutableDemo {
private final int[] myArray;
public ImmutableDemo(int[] array) {
this.myArray = array; // wrong
}
}
这种方式不能保证不可变性,myArray和array指向同一块内存地址,用户可以在ImmutableDemo之外通过修改array对象的值来改变myArray内部的值。为了保证内部的值不被修改,可以采用深度copy来创建一个新内存保存传入的值。
正确方式如下:
public final class MyImmutableDemo {
private final int[] myArray;
public MyImmutableDemo(int[] array) {
this.myArray = array.clone(); // right
}
}
(5)在getter方法中不能返回对象本身,而是返回对象的拷贝。
3、看看String类源码是如何构造不可变性的
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
{
/** The value is used for character storage. */
private final char value[];//0.private final
....
public String(char value[]) {//1.构造器深拷贝
this.value = Arrays.copyOf(value, value.length);
}
...
public char[] toCharArray() {
// Cannot use Arrays.copyOf because of class initialization order issues
char result[] = new char[value.length];
System.arraycopy(value, 0, result, 0, value.length);//2.返回对象拷贝
return result;
}
...
}
4、String对象的不可变性的优点
(1)线程安全。
(2)字符串常量池的需要。
只有当字符串是不可变的,字符串池才有可能实现。字符串常量池可以将一些字符常量放在常量池中重复使用,避免每次都重新创建相同的对象、节省存储空间。
(3)字符串很适合作为Map中的key。
5、String对象的是否真的不可变
虽然String对象将value设置为final,并且还通过各种机制保证其成员变量不可改变。但是还是可以通过反射机制的手段改变其值。
参考文档:
https://www.cnblogs.com/jaylon/p/5721571.html