除了用 Java 实现 Clone 之外,还有其他选择吗?

发布于 2024-07-17 14:22:20 字数 793 浏览 5 评论 0原文

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

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

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

我怎样才能在Java中实现这样的事情?

In my Java project, I have a vector of various types of Traders. These different types of traders are subclasses of the Trader class. Right now, I have a method that takes a Trader as an argument and stores it 50 or so times in the vector. I am having problems because storing the same object 50 times is just storing 50 references of the same object. I need to store 50 copies of the object. I've researched about implementing Clone, but I don't want the programmers defining a type of Trader to have to worry about making their class cloneable. Also, as pointed out by this page, implementing clone creates all sorts of problems. I don't think a copy constructor would work either because if I defined one in the Trader class, it would not know the type of Trader it was copying and just make a generic Trader. What can I do?

Edit: I am not really wanting to make exact copies of a certain object. What I am really trying to do is to add a certain number of Traders to the vector. The problem is that the user needs to specify in an argument which type of Trader he wants to add. Here is an example of what I am trying to do: (although my syntax is completely imaginary)

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

How can I achieve something like this in Java?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

梅窗月明清似水 2024-07-24 14:22:21

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

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

Just add an abstract copy method. You can use covariant return types so that the derived type is specified to return a derived instance, which may or may not be important.

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


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

Sometimes you might want to generically deal with a collection of derived type of Trader that needs to clone and then return the a properly typed collection. For that you can use generics in an idiomatic way:

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


public final class MyTrader implements Trader<MyTrader> {
    public MyTrader copyTrader() {
        return new MyTrader(this);
    }
    ...
}
诗化ㄋ丶相逢 2024-07-24 14:22:21

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

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

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

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

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

寻找绕过实际 Cloneable 和 Clone 的技巧并不能解决继承问题。 这里没有灵丹妙药。

I am a little unclear as to why you would want to store 50 or so clones of the same object unless they the original trader serves as a prototype (see pattern) for later traders.

If you want to make an exact copy of an object, you have to take into account the issue of polymorphism. If people subclassing your given class are allowed to add state members, then you already have enough of a headache with functions like equals and compareTo, that clone is jut one more case where you need to require special handling.

I disagree that clone is always evil, it is sometimes necessary. However, in situations of subclassing, a lot of things become tricky.

I would recommend you read (when you get a chance) Bloch's "Effective Java", which covers a lot of his topics. Bracha's view is that it is not a good idea to let others extend your classes, and that if you do, you need to document very well what they would have to do and hope that they follow your instructions. There really isn't a way to bypass that. You may also want to make your Traders immutable.

Go ahead an implement Clone normally, and indicate very clearly in the class header that anybody inheriting from your Trader and adding state members must implement X methods (specify which).

Finding tricks to bypass an actual Cloneable and still Clone isn't going to overcome the problem of inheritance. There is no silver bullet here.

治碍 2024-07-24 14:22:21

Uri 是对的,状态多态性带来了一大堆蠕虫。

我认为子类化 Cloneable 并重写 clone() 可能是最简单的方法。 我相信,您可以使返回类型协变。

Uri's right, polymorphism with state opens up a big can of worms.

I think subclassing Cloneable and overrideing clone() is probably the simplest way to go. You can, I believe, make the return type covariant.

°如果伤别离去 2024-07-24 14:22:21

一种选择:如果可以使对象可序列化,则可以序列化然后反序列化它以创建副本,类似于通过 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;
        }
    }
}

One option: If you can make the objects serializable, you can serialize then deserialize it to make a copy, similar to what happens when passing an object over RMI.

Quick copy method:

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;
        }
    }
}
稚气少女 2024-07-24 14:22:21

一种方法是使其成为像 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
    }
}

您甚至可以指定另一个重载方法,或第二个参数,它采用一个交易者并将其复制到一个新的交易者中,从而取代克隆。
顺便说一句,您可能想要重写clone()方法并抛出CloneNotSupportedException,以防止默认的对象克隆。

One way is to make it a final class like Java's own String, which will make any change to an object of class Trader to create a new copy in memory, but it will make it impossible to subclass it.

Another (better) way is to use a factory method to create and copy Trader objexts, which implies that you must not allow for the default constructor to be used i.e. make it a private. This way you can control the number of instances the class has.
See 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
    }
}

You might even specify another overloaded method, or a second argument that takes one Trader and copies it into a new one, thus replacing clone.
Btw, you might want to override the clone() method and throw CloneNotSupportedException, to prevent default Object cloning.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文