原始的类的设计如下
import java.util.Date;
public final class SafeMain {
private final Date start;
private final Date end;
private final int name;
public SafeMain(Date start,Date end,int name){
if (start.compareTo(end)>0) {
throw new IllegalArgumentException();
}
this.start = start;
this.end = end;
this.name = name;
}
public Date getStart() {
return start;
}
public Date getEnd() {
return end;
}
public int getName() {
return name;
}
@Override
public String toString() {
return "SafeMain [start=" + start + ", end=" + end + ", name=" + name
+ "]";
}
}
但是可能存在如下的攻击
public static void main(String[] args) {
//TOCTOU
//1
Date start = new Date();
Date end = new Date();
int name = 111;
SafeMain safeMain = new SafeMain(start, end,name);
end.setYear(78);
name = 23456;
System.out.println(safeMain.getEnd().getYear());
System.out.println(safeMain.toString());
//2
safeMain.getEnd().setYear(888);
}
最开始的设计是end大于start才满足要求.而且这里的start和end都是不可变的(按照原始的累的设计的要求是这样的),这2中攻击都使类的设计失效.
修正之后的类
public final class SafeMain {
private final Date start;
private final Date end;
private final int name;
public SafeMain(Date start,Date end,int name){
this.start = start;
this.end = end;
this.name = name;
if (this.start.compareTo(this.end)>0) {
throw new IllegalArgumentException();
}
}
public Date getStart() {
return new Date(start.getTime());
}
public Date getEnd() {
return new Date(end.getTime());
}
public int getName() {
return name;
}
@Override
public String toString() {
return "SafeMain [start=" + start + ", end=" + end + ", name=" + name
+ "]";
}
}
完美的避免了攻击
不止是在不可变的类的设计中这样保护性拷贝属性,某一些类的属性有一定的限制,在被后面的程序修改之后会产生不可预计的错误,也可以这样做.