clone()非最终类

时间:2016-11-29 09:58:47

标签: java clone

根据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

}

如果我修改一个accesor方法以使用clone函数返回日期对象的副本而不是使用这样的构造函数进行复制,我不会得到什么错误: -

public Date start() {
    return start.clone();
}

而不是

public Date start() {
       return new Date(start.getTime());
}

如何才能返回恶意子类的实例?

2 个答案:

答案 0 :(得分:3)

java.util.Date方法中使用提供防御性副本的clone()类,但这也不是最终版本。
假设我将Date子类化,并覆盖clone()方法 现在,在运行时,如果我收到此子类的实例,则不再使用Date的clone()。所以,我不确定子类的实现是否仍然是原始的防御性副本。

这:

public Date start() {
    return start.clone();
}
如果子类重写clone(),那么

将不会是防御性副本:

@Override 
public Object clone() {
    return this; 
}

答案 1 :(得分:0)

将为访问器方法返回恶意子类的实例。引用同一章-

  

在访问器中,与构造函数不同的是,   使用克隆方法制作防御副本。这是因为   我们知道Period内部Date对象的类是   java.util.Date,而不是一些可能不受信任的子类。

扩展

  

请勿使用clone方法制作参数的防御性副本   其类型可以由不受信任的方继承。

由于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;
        }
    }
}
相关问题