如果你不在Java中克隆那么你会怎么做,你会怎么称呼它?

时间:2021-02-23 21:11:31

Does anyone have any suggested or established best practices and naming conventions for copy constructors / factory methods etc in Java? In particular, say I have a class Thing and I want a method somewhere that returns a new Thing with the same value as a Thing passed in (or as the instance if it's an instance method). Would you have this as constructor or a static factory method or instance method? What would you call it?

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

As per the title, I want to avoid clone() and Cloneable.

就标题而言,我希望避免克隆()和克隆。

8 个解决方案

#1


16  

Effective Java recommends either of the following:

有效Java建议以下任何一种:

  1. A copy constructor (as noted by others):

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

    public Item(Item item)

    公共项目(项目项)

  2. A copy factory method:

    一份工厂方法:

    public static Item newInstance(Item item)

    公共静态项目newInstance(项目)

(Also, no copying for immutables)

(同时,不可复制

The primary difference is that with #1 you choose the actual class of the result, and with #2 the implementer can return a subclass. The semantics of the class may guide you into which one is best.

主要的区别在于,对于#1,您可以选择结果的实际类,对于#2,实现者可以返回一个子类。这门课的语义学可以引导你进入哪一门最好。

#2


3  

I would call it a copy method or a copy constructor (as the case may be). If it was a static method, then I would call it a factory.

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

In terms of what to do, the most flexible and long living option is a copy constructor. This gives subclasses the ability to copy themselves just like the parent.

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

#3


2  

I'd do a constructor

我会做一个构造函数

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

then when you want to clone it

然后当你想克隆它的时候

Thing copy = new Thing(copy from me);

#4


0  

You can overwrite the clone()-method, if you want. Another used practice is a constructor, that takes an object of this type, i.e. new ArrayList(anotherList).

如果需要,可以覆盖clone()方法。另一个常用的实践是构造函数,它接受这种类型的对象,即新的ArrayList(另一个list)。

#5


0  

You've got a few options, implement Cloneable, add a copy constructor but my preferred way is to use a method (static or instance) that has a name which is descriptive of what the copy operation is doing - is it a deep or shallow copy, etc.

您有一些选项,实现Cloneable,添加一个复制构造函数,但是我的首选方法是使用一个方法(静态或实例),该方法的名称描述了复制操作正在进行的操作——它是深度复制还是浅拷贝,等等。

#6


0  

Use immutable data structures. The only reason you feel that you need clone() is that you're mutating your objects in place. Stop doing that. Think about how you can:

使用不可变的数据结构。您认为需要克隆人()的唯一原因是您正在适当地改变您的对象。停止这样做。想想怎么做:

  • Make your classes final.
  • 最后让你的类。
  • Make fields in your classes final and private.
  • 使类中的字段成为最终的和私有的。

For example, here's a "setter" for an immutable 3D vector object:

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

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

So I guess what I'm saying is... I use copy constructors instead of mutation, and I just name them according to the attribute that I want to modify.

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

#7


0  

Another option is to implement the copying method in the source object, e.g.:

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

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

    void copyCoordsTo(Has3DCoords dest);
}

You would then implement copying with a piece of code like:

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

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

This can be useful if:

如果:

  • It does not make sense to clone the whole object
  • 克隆整个对象是没有意义的
  • There is a group of related properties that are often copied as one unit
  • 有一组相关的属性通常被复制为一个单元
  • You do not want to expose loc as a property of Thing
  • 您不希望将loc公开为事物的属性
  • The number of properties is large (or there are many such groups) so a constructor that required all of them as parameters would be unwieldy.
  • 属性的数量很大(或者有很多这样的组),因此需要将所有的属性作为参数的构造函数会很麻烦。

#8


0  

This is not the nicest approach to copying objects but the following is sometimes useful if you wish to perform a deep copy of a Serializable object. This avoids having to write copy constuctors, implement Cloneable or writing factory classes.

这不是最好的复制对象的方法,但是如果您希望执行可序列化对象的深度副本,以下方法有时是有用的。这避免了必须编写复制构造函数、实现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();

Don't forget to handle the exceptions and to close the streams nicely.

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

#1


16  

Effective Java recommends either of the following:

有效Java建议以下任何一种:

  1. A copy constructor (as noted by others):

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

    public Item(Item item)

    公共项目(项目项)

  2. A copy factory method:

    一份工厂方法:

    public static Item newInstance(Item item)

    公共静态项目newInstance(项目)

(Also, no copying for immutables)

(同时,不可复制

The primary difference is that with #1 you choose the actual class of the result, and with #2 the implementer can return a subclass. The semantics of the class may guide you into which one is best.

主要的区别在于,对于#1,您可以选择结果的实际类,对于#2,实现者可以返回一个子类。这门课的语义学可以引导你进入哪一门最好。

#2


3  

I would call it a copy method or a copy constructor (as the case may be). If it was a static method, then I would call it a factory.

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

In terms of what to do, the most flexible and long living option is a copy constructor. This gives subclasses the ability to copy themselves just like the parent.

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

#3


2  

I'd do a constructor

我会做一个构造函数

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

then when you want to clone it

然后当你想克隆它的时候

Thing copy = new Thing(copy from me);

#4


0  

You can overwrite the clone()-method, if you want. Another used practice is a constructor, that takes an object of this type, i.e. new ArrayList(anotherList).

如果需要,可以覆盖clone()方法。另一个常用的实践是构造函数,它接受这种类型的对象,即新的ArrayList(另一个list)。

#5


0  

You've got a few options, implement Cloneable, add a copy constructor but my preferred way is to use a method (static or instance) that has a name which is descriptive of what the copy operation is doing - is it a deep or shallow copy, etc.

您有一些选项,实现Cloneable,添加一个复制构造函数,但是我的首选方法是使用一个方法(静态或实例),该方法的名称描述了复制操作正在进行的操作——它是深度复制还是浅拷贝,等等。

#6


0  

Use immutable data structures. The only reason you feel that you need clone() is that you're mutating your objects in place. Stop doing that. Think about how you can:

使用不可变的数据结构。您认为需要克隆人()的唯一原因是您正在适当地改变您的对象。停止这样做。想想怎么做:

  • Make your classes final.
  • 最后让你的类。
  • Make fields in your classes final and private.
  • 使类中的字段成为最终的和私有的。

For example, here's a "setter" for an immutable 3D vector object:

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

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

So I guess what I'm saying is... I use copy constructors instead of mutation, and I just name them according to the attribute that I want to modify.

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

#7


0  

Another option is to implement the copying method in the source object, e.g.:

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

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

    void copyCoordsTo(Has3DCoords dest);
}

You would then implement copying with a piece of code like:

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

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

This can be useful if:

如果:

  • It does not make sense to clone the whole object
  • 克隆整个对象是没有意义的
  • There is a group of related properties that are often copied as one unit
  • 有一组相关的属性通常被复制为一个单元
  • You do not want to expose loc as a property of Thing
  • 您不希望将loc公开为事物的属性
  • The number of properties is large (or there are many such groups) so a constructor that required all of them as parameters would be unwieldy.
  • 属性的数量很大(或者有很多这样的组),因此需要将所有的属性作为参数的构造函数会很麻烦。

#8


0  

This is not the nicest approach to copying objects but the following is sometimes useful if you wish to perform a deep copy of a Serializable object. This avoids having to write copy constuctors, implement Cloneable or writing factory classes.

这不是最好的复制对象的方法,但是如果您希望执行可序列化对象的深度副本,以下方法有时是有用的。这避免了必须编写复制构造函数、实现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();

Don't forget to handle the exceptions and to close the streams nicely.

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