看下面这个例子
public final class Period
{
private final Date startTime;
private finale Date endTime;
public Period(Date startTime , Date endTime)
{
if(startTime.compareTo(endTime) > 0)
{ throw new IllegalArgumentException(“startTime after endTime !”); }
this.startTime = startTime;
this.endTime = endTime;
}
pubilc Date start()
{ return this.startTime ; }
public Date end()
{ return this.endTime ; }
}
上面这段程序乍一看是不可变的,但事实上它有许多漏洞。
Date startTime = new Date();
Date endTime = new Date();
Period per = new Period(startTime , endTime );
endTime.setYear(78);
我们通过改变Date类就可以改变Period,这时候我们就应该对构造器进行改造
public Period(Date startTime , Date endTime )
{
this.startTime = new Date (startTime.getTime());
this.endTime = new Date(endTime.getTime());
if(this.startTime.compareTo(this.endTime) > 0)
{
throw new IllegalArgumentException(“startTime after endTime !”);
}
}
但只是改变构造器也是不够的,start()、end()返回的Date也是可变的。如
per.start().setYear(78);
改造一下:
public Date start()
{
return new Date(startTime.getTime());
}
public Date end()
{
return new Date(endTime.getTime());
}
这样就真正实现了不可变。
保护性拷贝不仅仅只是针对不可变类。如果我们不能容忍对象进入数据结构后可以变化,我们也应该考虑保护性拷贝。
所以说我们应该尽量使用不可变的对象作为对象内部组件,这样就不必考虑保护性拷贝的问题了。
如果类具有从客户端得到或者返回客户端的可变组件,类就必须保护性地拷贝这些组件,如果拷贝成本受到限制,并且类信任调用者不会修改内部组件,不进行保护性拷贝也是可以的,类的文档必须清楚说明这一点。