可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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?
As per the title, I want to avoid clone()
and Cloneable
.
回答1:
Effective Java recommends either of the following:
A copy constructor (as noted by others):
public Item(Item item)
A copy factory method:
public static Item newInstance(Item item)
(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.
回答2:
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:
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:
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).
回答5:
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.
回答6:
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:
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:
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
- 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:
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.
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.