EffectiveJava(15)强化对象和域的不可变性

概念:
不可变类是其实例不能被修改的类,不可变类比可变类更加易于设计 实现和使用.它们不容易出错,而且更加安全.
优点
1.不可变对象只有创建时状态.
2.不可变对象本质上是线程安全的,它们不要求同步
3.不可变对象和其内部信息可以被自由共享.这条导致的结果是不可变类永远也不需要进行任何拷贝(拷贝对象始终为原始对象).
public static final Complex ZERO = new Complex(0.0);
4.不可变对象为其他对象提供了大量构件,其他对象无论是否可变.
缺点:
它只有唯一一个缺点:对于每个不同的值都需要单独创建一个对象
改变BigInteger的低位

BigInteger moby = new BigInteger("198");
        //多步骤操作,每个步骤都会创建一个对象,除了最后的结果之外,其他对象都会被抛弃
        moby = moby.flipBit(0);
        //它只有在需要进一的时候,才会自减一  199>198  100-198>101-199
        System.out.println(moby);
    运行之后我们可以看到,需要很长时间才能计算完成

针对它的性能问题(缺点)也有优化方法
    1.猜测会经常使用哪些多步骤操作,然后将他们作为基本类型提供
    2.提供一个公有的可变嵌套类:String的可变嵌套类为StringBuilder

不可变类创建规则:
1.不要提供任何会修改对象状态的方法
2.保证类不会被扩展:防止子类假装对象的状态已经改变而破坏该类的不可变行为
a.一般把类声明为final
b.让类的所有构造器都变成私有的或者包级私有的,并添加公有的静态工厂方法
有关于静态工厂方法,请跳转:http://blog.csdn.net/jacxuan/article/details/56849989

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

// 通过让类的所有构造器变成私有或者包级私有并添加公有的静态工厂来代替公有构造器来让不可变类变为final

private Complex(double re, double im) {
    this.re = re;
    this.im = im;
}
public static Complex valueOf(double re, double im) {
    return new Complex(re, im);
}
3.使所有域都是final的
4.使所有域都成为私有的:防止被域引用的可变对象的权限,并防止客户端直接修改这些对象.公有final域不建议
5.确保对于任何可变组件的互斥访问:如果类具有指向可变对象的域,则必须确保该类的客户端无法获得指向这些对象
  的引用.并且,永远不要用客户端提供的对象引用来初始化这样的域,也不要从任何访问方法中返回该对象的引用.
6.坚决不要为每个get方法编写一个相应的set方法.

创建一个不可变的类:
这个类表示一个复数(具有实部和虚部),他除了提供标准的Object方法之外,还提供了针对实部和虚部的访问方法
,以及四种混合运算.
注意这些算法运算是如何创建并返回新的Complex实例的

    public final class Complex {
    public final double re;
    public 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 + 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));
    }

    @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 ==
        // 见43页找出为什么我们使用比较而不是= =
        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 im2) {
        long longBits = Double.doubleToLongBits(re);
        return (int) (longBits ^ (longBits >>> 32));
    }

    @Override
    public String toString() {
        return "(" + re + "+" + im + "i)";
    }
}

ps:如果你正在编写一个安全性依赖于BigInteger或者BigDecimal参数的不可变性,就必须进行检查,
以确定这个参数是真正的BinInteger或BigDecimal,而不是不可信任的子类的实例.如果是后者的
话,必须假设它是可变的前提下对它进行可变性拷贝

    public static BigInteger safeInstance(BigInteger val){
        if(val.getClass()!=BigInteger.class)
            return new BigInteger(val.toByteArray());
        return val;
    }

总结:如果类不能被做成不可变的,仍然应该尽可能限制它的可变性.

原文地址:https://www.cnblogs.com/qwop/p/6637298.html