参考不可变类String的设计,说明一下不可变设计的要素

  1. public final class String
  2. implements java.io.Serializable, Comparable<String>, CharSequence {
  3. /** The value is used for character storage. */
  4. private final char value[];
  5. /** Cache the hash code for the string */
  6. private int hash; // Default to 0
  7. //其它方法...
  8. }

final的使用

发现该类、类中所有属性都是 final 的

  • 属性用 final 修饰保证了该属性只读,不能修改,一旦设置值就不可再改变。
  • 类用 final 修饰保证了该类中的方法不能被覆盖,防止子类无意间破坏不可变性,final 修饰的类实际上不可以被继承。

保护性拷贝

字符串类,当比较两个字符串是否相等时,如果直接用“=”比较,那么比较的是字符串引用,常说的字符串一旦定义就不可变,指的是类对象中的 private final char value[]是不变的,只有一份,如果调用substring方法,字符型数组value值仍不变,substring内部相当于再创建一个全新的String类对象返回。

String类-substring方法源码:

  1. public String substring(int beginIndex) {
  2. if (beginIndex < 0) {
  3. throw new StringIndexOutOfBoundsException(beginIndex);
  4. }
  5. int subLen = value.length - beginIndex;
  6. if (subLen < 0) {
  7. throw new StringIndexOutOfBoundsException(subLen);
  8. }
  9. return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
  10. }

保护性拷贝是可以保护线程安全的,例如多个线程调用substring方法,那么实际上不是多个线程对value数组访问操作,而是每个线程均得到一个新的String对象,这从根本上保护了线程安全,因为甚至多个线程访问的不是共享变量,每个线程独有。

注意:不可变类的单个方法是线程安全的,但不能保证方法的组合是线程安全的。