2016-11-12 51 views
-2

effective java中声明的项目:在需要时制作防御副本,不使用克隆方法制作一个参数的防御副本,其类型可由不受信任的子副本派对在创建防御副本时创建新对象而不是克隆

我无法理解这实际上是什么意思。

+0

如果第三方为你的班级分类,你不知道'clone()'可能会做什么。对于大多数项目来说,这会担心某些不太可能成为问题的事情,但是对于JDK来说,这是他们必须关注的事情。 –

回答

2

下面是该书在该部分中突出显示的关注。

public MyOtherClass implements Cloneable { 
    public Object clone() { 
     super.clone(); 
    } 
} 

public MyOtherClass { 
    private MyClass m; 

    public MyOtherClass(MyClass m) { 
     this.m = m.clone(); // Defensive copy. 
    } 
} 

public SneakyClass extends MyClass { 
    public clone() { 
     return this;   // !!!!!! 
    } 
} 

通过传递SneakyClass实例到MyOtherClass构造,有人能打败防守副本的构造函数试图做的。如您所见,覆盖clone()不会返回目标对象的副本。

(在这种情况下的解决方案,如果申报MyClass作为final或声明MyClass.clone()final。)

1

你所谈论的是介绍如何正确地实现一个不可变类的项目。

全款说:

还请注意,我们没有使用日期的克隆方法,使防守副本。因为Date是非终结的,所以克隆方法不保证返回一个类为java.util.Date的对象;它可能会返回专门为恶意恶作剧设计的不可信子类的实例。例如,这样的子类可以在其创建时记录对私有静态列表中每个实例的引用,并允许攻击者访问该列表。这会让攻击者自由掌控所有实例。为了防止这种攻击,不使用克隆方法来制作其类型可由不受信任方进行分类的参数的防御副本。

要显示什么款的其余部分被描述,想象一个clone方法做:

public class Foo implements Cloneable { 
    private int bar; 
    private static List<Foo> secretList = new ArrayList<>(); 

    public Foo(int bar) { this.bar = bar; } 

    @Override 
    public Foo clone() { 
     Foo copy = new Foo(this.bar); 
     secretList.add(copy); // this is the line of concern 
     return copy; 
    } 
} 

现在Foo类仍然可以访问它创建的实例,这意味着它可以恶意修改该实例即使它是不可变类的成员。

+0

长话短说*克隆对象总是根据原始对象的变化进行修改,这是一个坏主意* – emotionlessbananas