【Effective Java 17】使可变性最小化

不可变类是指其实例不能被修改的类。每个实例中包含的所有信息都必须在创建该实例的时候就提供,并在对象的整个生命周期(lifetime)内固定不变。Java 平台类库中包含许多不可变的类,其中有 String、基本类型的包装类、BigIntegerBigDecimal。存在不可变的类有许多理由:不可变的类比可变类更加易于设计、实现和使用。它们不容易出错,且更安全。

1. 使类成为不可变,要遵循下面五条原则

  1. 不要提供任何会修改对象状态的方法(如各种getset方法)
  2. 保证类不会被扩展。(禁止继承)
  3. 声明所有的域都是 final 的
  4. 声明所有的域都是私有的
  5. 确保对于任何可变组件的互斥访问

2. 不可变类的例子

下面展示编写一个不可变的复数类的例子。所有的运算函数都不会改变原有对象的值,而是将运算结果以新值返回。

public final class Complex {
    private final double re;
    private final double im;

    public Complex(double re, double rm) {
        this.re = re;
        this.im = rm;
    }

    public double realPart() {
        return re;
    }

    public double imaginaryPart() {
        return im;
    }

    public Complex plus(Complex c) {
        return new Complex(re + c.re, im + c.im);
    }

    public Complex minus(Complex c) {
        return new Complex(re - c.re, im - c.im);
    }

    public Complex times(Complex c) {
        return new Complex(re * c.re - im * c.im, re * c.im + im * c.re);
    }

    public Complex dividedBy(Complex c) {
        double tmp = c.re * c.re + c.im * c.im;
        return new Complex(
                (re * c.re + im * c.im) / tmp,
                (re * c.re - im * c.im) / tmp
        );
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Complex complex = (Complex) o;
        return Double.compare(complex.re, re) == 0 && Double.compare(complex.im, im) == 0;
    }

    @Override
    public int hashCode() {
        return Objects.hash(re, im);
    }

    @Override
    public String toString() {
        return String.format("(%f%+fi)", re, im);
    }

    public static void main(String[] args) {
        Complex c1 = new Complex(1.2, 2.2);
        Complex c2 = new Complex(1.6, 1.7);

        System.out.println(c1.times(c2));
    }
}

3. 不可变类的优缺点

  • 优点
    • 不可变对象比较简单:不可变对象可以只有一种状态,即被创建时的状态。
    • 不可变对象本质上是线程安全的,不要同步:不可变对象可以被自由共享,进而可以创建一些静态的常用对象,避免垃圾回收带来的影响
    • 不可变对象可以共享它们内部的信息
    • 不可变对象为其他对象提供大量的构件
    • 不可变对象无偿地提供了失败的原子性
  • 缺点:
    • 对于每个不同值都需要一个单独的对象

4. 总结

  • 尽可能少地编写set方法。除非有很好的理由要让类成为可变的类,否则它就应该是不可变的。-

  • 如果类不能做成不可变的,应该尽可能限制其可变性。

  • 每个域尽可能是 private final

  • 构造器应该创建完全初始化的对象,并建立起所有的约束关系。不要在构造器或静态工厂之外再提供公有的初始化方法。

posted on 2022-04-21 13:45  Silgm  阅读(50)  评论(0)    收藏  举报

导航