不可变类只是其实例不能修改的类。每个实例中包含的所有信息都必须在创建该实例的时候提供,并在对象的整个生命周期内固定不变。
Java平台类库中包含许多不可变的类,其中就有String,基本类型的包装类。BigInteger和BidDdcimal。
存在不可变的类有有许多理由:(相对于可变的类)
1.容易设计,实现和使用,
2.不容出错,且更加安全。
实现不可变类需要遵守以下规则:
1.不要提供任何会修改对象状态的方法。
2.保证类不会被扩展
3.使所有的域都是final。
4.是所有的域都是私有的
5.确保对于任何可变组件的互斥访问。
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 iml;}
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.re+im*c.im);
}
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)x;
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+"");
}
}
不可变类的优点:
1.不可变类对象比较简单。
2.不可变对象本质上是线程安全的,它们不要求同步。
例如:
public static final Complex ZERO=new Complex(0,0);
public static final Complex ONE =new Complex(1,0);
public static final Complex I =new Complex(0,1);
这种方法可以被进一步扩展。不可变的类可以提供一些静态工厂,它们把频繁被请求的实例缓存起来,从而当现有实例可以符合请求的时候,就不必创建新的实例。
3.”不可变对象可以被自由的共享“导致的结果,永远也不需要进行保护性拷贝。
4.不仅可以共享不可变对象,甚至也可以共享他们的内部信息
5.不可变对象为其他对象提供了大量的构件,无论是可变还是不可变的对象。
不可变类真正唯一的缺点是,对于每个不同的值都需要一个单独的对象。创建这种对象的代价很高,特别是对于大型对象的情形。
不可变类变成final的另一种办法就是,静态工厂方法。
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 static Complex valueOf(double re,double im){
return new Complex(re,im);
}
...
}
虽然这种方法并不常用,但他经常是最好的代替方法。