6

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

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

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

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

4

5 回答 5

2

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

public interface Trader {
    Trader copyTrader();
    ...
}


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

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

public interface Trader<THIS extends Trader> {
    THIS copyTrader();
    ...
}


public final class MyTrader implements Trader<MyTrader> {
    public MyTrader copyTrader() {
        return new MyTrader(this);
    }
    ...
}
于 2009-04-26T23:27:15.827 回答
2

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

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

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

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

继续正常实现 Clone,并在类头中非常清楚地指出任何从您的 Trader 继承并添加状态成员的人都必须实现 X 方法(指定哪个)。

寻找绕过实际 Cloneable 并且仍然 Clone 的技巧并不能克服继承问题。这里没有灵丹妙药。

于 2009-04-26T23:31:18.920 回答
0

一种选择:如果可以使对象可序列化,则可以对其进行序列化然后反序列化以制作副本,类似于通过 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;
        }
    }
}
于 2009-04-26T23:13:51.333 回答
0

Uri 说得对,状态多态性打开了一大堆蠕虫。

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

于 2009-04-27T02:49:19.600 回答
-2

一种方法是使其成为类似于 Java 自己的 String 的 final 类,这将对 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() 方法并抛出 CloneNotSupportedException,以防止默认对象克隆。

于 2009-04-26T23:29:24.307 回答