博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Item 15 Minimize mutability
阅读量:6656 次
发布时间:2019-06-25

本文共 2621 字,大约阅读时间需要 8 分钟。

不可变类是其实例不能被修改的类。 比如String、基本数据类型的包装类(String的基本数据类型就是String)、BigIntegerBigDecimal

要使一个类变成不可变的,要遵守下面的规则:

  1. 不提供任何修改对象状态的方法。比如setter getter中的setter(也称作mutator)就不能提供。

  2. 保证类不被扩展。通常用finla class实现(也可以用private构造函数的方法,也就是静态工厂方法里提到的)。

  3. 所有的fileds都设成私有的、final的。

4、 Ensure exclusive access(互斥访问) to any mutable components.

下面贴一段很长的代码,是一个复数运算的类:

public final class Complex {    private final double re;    private final double im;    public Complex(double re, double im) {        this.re = re;        this.im = im;    }    // Accessors with no corresponding mutators    public double realPart() {        return re;    }    public double imaginaryPart() {        return im;    }    public Complex add(Complex c) {        return new Complex(re + c.re, im + c.im);    }    public Complex subtract(Complex c) {        return new Complex(re - c.re, im - c.im);    }    public Complex multiply(Complex c) {        return new Complex(re * c.re - im * c.im,                re * c.im + im * c.re);    }    public Complex divide(Complex c) {        double tmp = c.re * c.re + c.im * c.im;        return new Complex((re * c.re + im * c.im) / tmp,                (im * c.re - re * c.im) / tmp);    }    @Override    public boolean equals(Object o) {        if (o == this)            return true;        if (!(o instanceof Complex))            return false;        Complex c = (Complex) o;// See page 43 to find out why we use compare instead of ==        return Double.compare(re, c.re) == 0 &&                Double.compare(im, c.im) == 0;    }    @Override    public int hashCode() {        int result = 17 + hashDouble(re);        result = 31 * result + hashDouble(im);        return result;    }    private int hashDouble(double val) {        long longBits = Double.doubleToLongBits(re);        return (int) (longBits ^ (longBits >>> 32));    }    @Override    public String toString() {        return "(" + re + " + " + im + "i)";    }}复制代码

可以看到这个类符合了上面列出来的要求。有个特点,每次计算完成之后都new一个实例,而不是修改传进来的。不可变类可以只有一种状态,就是创建时的状态。

不可变类天生就是线程安全的,不要求同步。多个线程并发访问的时候不会遭到破坏。所以可以被自由地共享。所以你根本不需要给不可变类提供拷贝构造器

坚决不要为每个getter都配置一个setter。除非有很好的理由让类变成可变的,不然他就应该是不可变的。

缺点

不可变类唯一的缺点是,对于每一个类不同的值都需要一个但对的对象。比如要创建几百万个BigInteger

BONUS:

我一直疑惑为什么String可以用=来初始化,而不用new;后来想了想,因为String是符合类型呀,它的基本数据类型和包装数据类型都是String。 :

String password="ok";利用到了字符串缓冲池,也就是说如果缓冲池中已经存在了相同的字符串,就不会产生新的对象,而直接返回缓冲池中的字符串对象的引用。 如: String a = "ok"; String b = "ok"; String c = new String("ok"); String d = new String("ok"); System.out.println(a==b);//将输出"true";因为两个变量指向同一个对象。 System.out.println(c==d);//将输出"flase";因为两个变量不指向同一个对象。虽然值相同,只有用c.equals(d)才能返回true.

转载于:https://juejin.im/post/5a3133fcf265da4327183b05

你可能感兴趣的文章