不要使用克隆方法来制作参数的防御副本 谁的类型是由不信任的各方进行下组。
现在仅从他的书中拿出一位专家: -
public final class Period {
private final Date start;
private final Date end;
/**
* @param start the beginning of the period
* @param end the end of the period; must not precede start
* @throws IllegalArgumentException if start is after end
* @throws NullPointerException if start or end is null
*/
public Period(Date start, Date end) {
if (start.compareTo(end) > 0)
throw new IllegalArgumentException(
start + " after " + end);
this.start = start;
this.end = end;
}
public Date start() {
return start;
}
public Date end() {
return end;
}
... // Remainder omitted
}
如果我修改了使用克隆函数返回日期对象的副本,而不是使用这样的构造函数返回日期对象的副本,则不会遇到错误的情况: -
public Date start() {
return start.clone();
}
而不是
public Date start() {
return new Date(start.getTime());
}
如何返回恶意子类的实例?
参加java.util.Date
类,该类别在其clone()
方法中提供防御副本,但也不是最终的。
假设我子类Date
,然后覆盖clone()
方法。
现在,在运行时,如果我收到此子类的实例,则日期的clone()
不会使用。因此,我不确定儿童班的实施是否仍将防御副本作为原始副本。
这个:
public Date start() {
return start.clone();
}
如果子类覆盖clone()
,则不会是防御副本:
@Override
public Object clone() {
return this;
}
恶意子类的实例将返回访问者方法。引用同一章 -
在饰品中,与构造函数不同,它是允许的 使用克隆方法制作防御副本。这是因为 我们知道
Period
的内部Date
对象是java.util.Date
,而不是一些潜在的不信任子类。
在
上扩展一点不要使用克隆方法来制作参数的防御副本 谁的类型是由不信任的各方进行下组。
由于Date
不是最终的,因此可以将其转换为改变其行为,因此Date
的克隆方法可以很好地返回恶意子类的实例。
示例
public class TestNonFinalCloneIssue {
public static void main(String[] args) {
NonFinalDate start = new NonFinalDate();
NonFinalDate end = new NonFinalDate();
Period p = new Period(start, end);
// We are completely obvious to the fact that copies of our data
// exists in another malicious class
System.out.println("Secretly copied data - " + NonFinalDate.MaliciousDate.getListOfInstances());
}
}
final class Period {
private final NonFinalDate start;
private final NonFinalDate end;
public Period(NonFinalDate start, NonFinalDate end){
NonFinalDate s = start.clone();
NonFinalDate e = end.clone();
if (s.compareTo(e) > 0){
throw new IllegalStateException(start + " after " + end);
}
this.start = s;
this.end = e;
}
}
class NonFinalDate extends Date{
@Override
public NonFinalDate clone(){
// NonFinalDate returning a malicious subclass (subclassing possible only because NonFinalDate is not final)
return new MaliciousDate(this);
}
static class MaliciousDate extends NonFinalDate {
private static List<NonFinalDate> listOfInstances = new ArrayList<>();
public MaliciousDate(NonFinalDate date){
// Secretly making copies of the data
listOfInstances.add(date);
}
public static List<NonFinalDate> getListOfInstances() {
return listOfInstances;
}
}
}