在Java中实现Clone还有其他选择吗?

在我的Java项目中,我有一个各种类型的交易者的向量。 这些不同类型的交易者是Trader类的子类。 现在,我有一个方法,以Trader作为参数,并在向量中存储50次左右。 我遇到了问题,因为存储相同的对象50次只是存储同一对象的50个引用 。 我需要存储50 对象的副本 。 我已经研究过如何实现Clone ,但是我不希望定义一种Trader的程序员不必担心让他们的类可以克隆 。 此外,正如本页所指出的,实现克隆会产生各种问题。 我认为复制构造函数不会起作用,因为如果我在Trader类中定义了一个,它就不会知道它正在复制的Trader的类型,只是制作一个通用的Trader。 我能做什么?

编辑:我不是真的想要制作某个对象的精确副本。 我真正想要做的是在向量中添加一定数量的交易者。 问题是用户需要在参数中指定他想要添加的交易者类型。 这是我想要做的一个例子:(虽然我的语法完全是想象的)

public void addTraders(*traderType*) { tradervect.add(new *traderType*()) } 

我怎样才能在Java中实现这样的目标?

只需添加一个抽象的复制方法。 您可以使用协变返回类型,以便指定派生类型以返回派生实例,这可能重要也可能不重要。

 public interface Trader { Trader copyTrader(); ... } public final class MyTrader implements Trader { MyTrader copyTrader() { return new MyTrader(this); } ... } 

有时您可能希望一般性地处理需要克隆然后返回正确类型的集合的派生类型的Trader集合。 为此,您可以以惯用的方式使用generics:

 public interface Trader { THIS copyTrader(); ... } public final class MyTrader implements Trader { public MyTrader copyTrader() { return new MyTrader(this); } ... } 

我有点不清楚你为什么要存储同一个对象的50个左右的克隆,除非原始交易者作为后期交易者的原型(见模式)。

如果要制作对象的精确副本,则必须考虑多态性问题。 如果允许子类化给定类的人员添加状态成员,那么你已经对equals和compareTo等函数感到头疼,那么克隆就是另外一个需要特殊处理的情况。

我不同意克隆总是邪恶的,有时是必要的。 但是,在子类化的情况下,很多事情变得棘手。

我建议你阅读(当你有机会的时候)Bloch的“Effective Java”,它涵盖了很多他的主题。 Bracha的观点是,让别人扩展你的课程不是一个好主意,如果你这样做,你需要很好地记录他们必须做什么,并希望他们遵循你的指示。 真的没有办法绕过那个。 您可能还想让您的交易者不可变。

正常地执行一个实现Clone,并在类头中清楚地指出任何从您的Traderinheritance并添加状态成员的人必须实现X方法(指定哪个)。

找到绕过实际Cloneable并仍然克隆的技巧不会克服inheritance问题。 这里没有银弹。

Uri是对的,与州的多态性开辟了一大堆蠕虫。

我认为inheritanceCloneable并覆盖clone()可能是最简单的方法。 我相信你可以使返回类型协变。

一个选项:如果可以使对象可序列化,则可以序列化然后反序列化它以创建副本,类似于通过RMI传递对象时发生的情况。

快速复制方法:

 public MyObject copy() { ObjectOutputStream oos = null; ObjectInputStream ois = null; try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(bos); oos.writeObject(this); oos.flush(); ByteArrayInputStream bin = new ByteArrayInputStream(bos.toByteArray()); ois = new ObjectInputStream(bin); return (MyObject)ois.readObject(); } catch(Exception e) { return null; } finally { try { oos.close(); ois.close(); } catch (Exception e) { return null; } } } 

一种方法是使它成为像Java自己的String这样的最终类,它将对类Trader的对象进行任何更改以在内存中创建新副本,但是它将无法对其进行子类化。

另一种(更好的)方法是使用工厂方法来创建和复制Trader对象,这意味着您不能允许使用默认构造函数,即将其设置为私有。 这样您就可以控制类具有的实例数。 见http://en.wikipedia.org/wiki/Factory_method

 public class Trader { /* prevent constructor so new cant be used outside the factory method */ private Trader() { } /* the factory method */ public static Trader createTrader(int whatKindOfTrader) { switch (whatKindOfTrader) { case 0: return new Trader1(); // extends Trader case 1: default: return new Trader2(); // extends Trader } return new Trader3(); // or throw exception } } 

您甚至可以指定另一个重载方法,或者第二个参数,它接受一个Trader并将其复制到一个新的,从而替换clone。 顺便说一句,您可能希望覆盖clone()方法并抛出CloneNotSupportedException,以防止默认的Object克隆。