如果你没有用Java克隆那么你做了什么以及你称之为什么?

有没有人在Java中有任何建议或建立的最佳实践和复制构造函数/工厂方法等的命名约定? 特别是,假设我有一个类Thing ,我想要一个方法,返回一个新的Thing ,其值与传入的Thing相同(或者作为实例,如果它是一个实例方法)。 你有这个作为构造函数或静态工厂方法或实例方法? 你会怎么称呼它?

根据标题,我想避免使用clone()Cloneable

Effective Java建议使用以下任一方法:

  1. 复制构造函数(如其他人所述):

    公共物品(物品项目)

  2. 复制工厂方法:

    public static Item newInstance(Item item)

(另外,不能复制不可变的)

主要区别在于,使用#1选择结果的实际类,使用#2,实​​现者可以返回子类。 课程的语义可以指导你哪一个是最好的。

我称之为复制方法或复制构造函数(视情况而定)。 如果它是静态方法,那么我将其称为工厂。

就做什么而言,最灵活和最长寿的选择是复制构造函数。 这使子类能够像父对象一样复制自己。

我会做一个构造函数

 ... public Thing(Thing copyFrom) { attr1 = copyFrom.attr1; attr2 = copyFrom.attr2; //etc... } 

然后当你想要克隆它

 Thing copy = new Thing(copy from me); 

如果需要,您可以覆盖clone() – 方法。 另一种使用的做法是构造函数,它接受这种类型的对象,即新的ArrayList(anotherList) 。

你有几个选项,实现Cloneable ,添加一个拷贝构造函数,但我首选的方法是使用一个方法(静态或实例),其名称描述了复制操作正在做什么 – 是深还是浅复制等

使用不可变数据结构 。 您认为需要clone()的唯一原因是您正在改变对象。 别那样做。 想想你怎么做:

  • 让你的课程最终。
  • 使您的class级中的字段成为最终和私有。

例如,这是一个不可变3D矢量对象的“setter”:

 public Vector3D setX(double x) { return new Vector3D(x, this.y, this.z); } 

所以我想我所说的是……我使用复制构造函数而不是变异,我只是根据我想要修改的属性命名它们。

另一种选择是在对象中实现复制方法,例如:

 interface Has3DCoords { void setLocation(double x, double y, double z); void copyCoordsTo(Has3DCoords dest); } 

然后,您将使用一段代码实现复制,例如:

 class Thing implements Has3DCoords { private Point3D loc; // ... void setLocation(double x, double y, double z) { loc.setLocation(x, y, z); // or: loc = new Point3D(x, y, z); } void copyCoordsTo(Has3DCoords dest) { loc.copyCoordsTo(dest); // or: dest.setLocation(loc.getX(), loc.getY(), loc.getZ()); } OtherThing createOtherThing() { OtherThing result = new OtherThing(); this.copyCoordsTo(result); return result; } } 

这在以下情况下非常有用:

  • 克隆整个对象没有意义
  • 有一组相关属性经常被复制为一个单元
  • 您不希望将loc公开为Thing的属性
  • 属性的数量很大(或者有很多这样的组),因此需要所有这些属性作为参数的构造函数会很笨重。

这不是复制对象的最佳方法,但如果您希望执行Serializable对象的深层副本 ,则以下内容有时很有用。 这避免了必须编写复制构造函数,实现Cloneable或编写工厂类。

 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); //Serializes the input object oos.writeObject(input); ByteArrayInputStream bais = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); //Copy of the input object Object output = ois.readObject(); 

不要忘记处理exception并很好地关闭流。