简体   繁体   English

clone()非最终类

[英]clone() non final classes

As per Josh Bloch's Effective java :- 根据Josh Bloch的有效java: -

do not use the clone method to make a defensive copy of a parameter whose type is subclassable by untrusted parties. 不要使用clone方法制作一个参数的防御性副本,该参数的类型可由不信任方进行子类化。

Now taking a expert from his book only:- 现在只从他的书中找专家: -

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

} }

I do not get what wrong would happen if I modify a accesor method to return a copy of date object using clone function instead of copy using constructor like this :- 如果我修改一个accesor方法使用clone函数返回日期对象的副本而不是使用像这样的构造函数复制,我不会得到什么错误: -

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

instead of 代替

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

How possibly can a instance of malicious subclass be returned? 怎么可能返回恶意子类的实例?

Take the java.util.Date class which provides a defensive copy in its clone() method but which is also not final. java.util.Date类为例,该类在其clone()方法中提供防御性副本,但也不是最终的。
Suppose I subclass Date and I override the clone() method. 假设我是Date子类,我重写了clone()方法。
Now, at runtime, if I receive an instance of this subclass, clone() of Date is not used anylonger. 现在,在运行时,如果我收到此子类的实例,则不再使用Date的clone() So, I am not sure that the implementation of the child class makes still a defensive copy as the original. 所以,我不确定子类的实现是否仍然是原始的防御性副本。

This : 这个 :

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

will not be a defensive copy if a subclass overrides clone() like that : 如果子类重写clone() ,则不会是防御性副本:

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

Instance of malicious subclass be returned for the accessor method. 为访问器方法返回恶意子类的实例。 Quoting from the same chapter - 引用同一章 -

In the accessors, unlike the constructor, it would be permissible to use the clone method to make the defensive copies. 在访问器中,与构造函数不同,允许使用克隆方法来制作防御性副本。 This is so because we know that class of Period 's internal Date objects is java.util.Date , and not some potentially untrusted subclass. 这是因为我们知道Period的内部Date对象的类是java.util.Date ,而不是一些可能不受信任的子类。

Expanding a bit on 扩大一点

do not use the clone method to make a defensive copy of a parameter whose type is subclassable by untrusted parties. 不要使用clone方法制作一个参数的防御性副本,该参数的类型可由不信任方进行子类化。

Since Date is not final, it can be subclassed to change its behavior so the clone method of Date could very well return an instance of a malicious subclass. 由于Date不是final,因此可以将其子类化以更改其行为,因此Date的clone方法可以很好地返回恶意子类的实例。

Example

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM