java.util.Date克隆或复制以不公开内部引用

Ral*_*lph 64 java clone

最佳做法是不公开Object(Entity)的内部引用.因此,如果一个Object有一个类型的字段,java.util.Date那么例如该字段的getter应该不返回原始日期而是它的副本.

但是对于java.util.Date,有两种常见的方法来创建该副本:

  • 克隆: (Date) originalDate.clone()
  • 通过构造函数复制 new Date(originalDate.getTime())

我的问题是,哪种方式更好,为什么?

Jon*_*eet 43

如果它绝对只是一个Date,它不会有任何区别.

如果实际对象可能是(例如)的子类,那么我希望保留额外的信息(包括它是哪个类),而调用构造函数则不行.Datejava.sql.Dateclone()

顺便说一句,如果你使用Joda Time你就不会有这个问题,因为有很多不可变的类型可供使用.它也是一个更好的API :)

  • 从Java 8开始,可以使用java.time API代替Joda Time. (7认同)

Ami*_*ani 35

阅读有效的Java.创建副本的首选方法是使用复制构造方法.

Bill Venners:在你的书中,你建议使用复制构造函数,而不是实现Cloneable和编写克隆.你能详细说明吗?

Josh Bloch:如果你已经阅读了我的书中关于克隆的项目,特别是如果你在阅读之间阅读,你就会知道我认为克隆已经深受打击.存在一些设计缺陷,其中最大的一个是Cloneable接口没有克隆方法.这意味着它根本不起作用:制作一些Cloneable并没有说明你可以用它做什么.相反,它说明了内部可以做些什么.它说如果通过反复调用super.clone它最终调用Object的clone方法,这个方法将返回原始的字段副本.

  • 这是在您自己的类中设计克隆的首选方法,尽管它要求调用者*知道*使用哪个具体子类*关注*使用哪个具体子类.请参阅我的答案,了解它如何有所作为. (6认同)

rob*_*pvn 15

如果你在防御性编码,你会想要复制构造函数.请参阅Effective Java的这篇文章:

另请注意,我们没有使用Date的克隆方法来制作防御性副本.因为Date是非最终的,所以不能保证clone方法返回一个类为java.util.Date的对象; 它可以返回一个专门为恶意恶作剧设计的不受信任的子类的实例.例如,这样的子类可以在创建私有静态列表时记录对每个实例的引用,并允许攻击者访问该列表.这将使攻击者在所有实例中自由统治.要防止此类攻击,请不要使用clone方法制作类型可由不信任方进行子类化的参数的防御副本.