不可变的类是指这个类被实例化了后,不能被修改。类的成员变量必须是在创建的时候被赋值,并在对象被销毁钱不会改变。java 中的 String 基本类型包装类 BigInterger 等都属于这方面的例子
。这样设计的好处是 易于设计 不容易出错,更安全。我们设计这种类型的类时,要遵循五大原则:
一、不要提供任何可以改变成员变量值的方法。 也就是说这个类的成员变量,不要对外暴露方法,从而可以改变它的值,例如 setter方法 ;
二、保证类不会被扩展。 防止恶意创作一个子类,然后通过子类来改变父类的一些属性,final 就可以起作用,用它修饰类,就不能被继承了;
三、使所有的域都成为私有的。这句话的意思是 把成员变量和自己的方法,都使用 final 来修饰,作用如上一条,保证它们不能被修改;
四、使所有的域都成为私有的。 意思是 把成员变量和自己的方法,都使用 private 来修饰,这样,通过该类的对象就不能修改成员变量的值了;
五、确保对于任何可变组件的互斥访问。 这句话有点不好理解,一般情况用不到。一般来说,注意构造器 访问方法 和 readObject中使用保护性拷贝,可以重新创造一个对象,不要几个方法共同产
生一个对象。
public final class Complex {
private final double re;
private final double im;
public Complex(double re, double im) {
this.re = re;
this.im = im;
}
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,
(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 47 to find out why we use compare instead of ==
return Double.compare(c.re, re) == 0 && Double.compare(c.im, im) == 0;
}
@Override public int hashCode() {
return 31 * Double.hashCode(re) + Double.hashCode(im);
}
@Override public String toString() {
return "(" + re + " + " + im + "i)";
}
}
书上这个例子就很完美。这个类及成员变量和方法,都被 final 修饰,(除了从父类继承的公共方法)。该类不会被继承,没有set方法改变属性的值,传入一个对象,也是通过方法去构造一个新的对
象,即使几个方法同时调用,也不会返回相同的一个对象。Complex c1 = new Complex(1, 1); 如果觉得不方便,可以修改类,提供静态工厂方法。
public class Complex {
private final double re;
private final double im;
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);
}
}
Complex c2 = Complex.valueOf(1, 1);
对外千万不要提供set和get方法,不要改变对象的值。这种写法好处多,当然也有坏处,就是可能会创造大量的对象,浪费性能。