克隆()非最终类.根据Josh Bloch的有效Java: -



不要使用克隆方法来制作参数的防御副本 谁的类型是由不信任的各方进行下组。

现在仅从他的书中拿出一位专家: -

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;
        }
    }
}

最新更新