0

考虑以下情况:

我为嵌入式(调制解调器)设备编写了一个 java 程序。SDK 不提供 Cloneable。因此我有class GsmSignalStrength方法clone(),但它不是来自Object.clone(),它是“我的”实现。我想知道这是否有用且正确,或者我应该GsmSignalStrength在评论中使用复制构造函数吗?我看不到复制构造函数的优势,因为我必须在我的 StateMachine 中创建另一个 GsmSignalStrength 对象。

这是我的代码...

文件 1“Status.java”:

class Status
{
    Status(GsmSignalStrength gsmSignalStrength)
    {
        initClass(gsmSignalStrength);
    }

    GsmSignalStrength gsmSignalStrength;

    private void initClass(GsmSignalStrength gsmSignalStrength)
    {
        this.gsmSignalStrength = gsmSignalStrength;
    }
}

文件 2“GsmSignalStrength”:

class GsmSignalStrength
{
    GsmSignalStrength(byte signalStrength)
    {
        initClass(signalStrength);
    }

    GsmSignalStrength()
    {
        initClass(100);
    }

    byte value;

    public void copyTo(GsmSignalStrength destination)
    {
        destination.value = this.value;
    }

    public GsmSignalStrength clone()
    {
        GsmSignalStrength clonedValue = new GsmSignalStrength();

        this.copyTo(clonedValue);

        return clonedValue;
    }

    /* With copy constructor
        GsmSignalStrength(GsmSignalStrength gsmSignalStrength)
        {
            gsmSignalStrength.value = value;
        }
    */

    private void initClass(byte signalStrength)
    {
        this.value = signalStrength;
    }
}

文件 5“GsmModemHandler”:

class GsmModemHandler
{
    GsmModemHandler()
    {
        initClass();
    }

    private GsmSignalStrength m_gsmSignalStrength;

    GsmSignalStrength getGsmSignalStrength()
    {

        ...bla...

        return m_gsmSignalStrength;
    }

    private void initClass()
    {
        m_gsmSignalStrength = new GsmSignalStrength();
    }
}

文件 4“状态机”:

class StateMachine
{
    StateMachine(GsmModemHandler gsmModemHandler)
    {
        initClass(gsmModemHandler);
    }

    private GsmModemHandler m_gsmModemHandler;

    void doSomething()
    {
        GsmSignalStrength gsmSignalStrength = m_gsmModemHandler.getGsmSignalStrength();
        Status xy = new Status(gsmSignalStrength.clone());

        /* With copy constructor

            GsmSignalStrength gsmSignalStrengthCopy = new GsmSignalStrength(gsmSignalStrength);
            Status xy = new Status(gsmSignalStrengthCopy);
        */
    }

    private void initClass(GsmModemHandler gsmModemHandler)
    {
        m_gsmModemHandler = gsmModemHandler;
    }
}
4

2 回答 2

4

你什么在那条评论中,

GsmSignalStrength(GsmSignalStrength gsmSignalStrength)
    {
        gsmSignalStrength = this;
    }

不是复制构造函数。线

gsmSignalStrength = this;

完全没有效果,因为它所做的只是将方法本地引用移动到指向this.

一个正常运行的“复制构造函数”将类似于

GsmSignalStrength(GsmSignalStrength gsmSignalStrength)
    {
        this.value = gsmSignalStrength.value;
    }

重点是创建一个与原始对象具有相同成员变量的独立对象。

此外,与 C++ 不同,编写

object1 = object2;

调用复制构造函数。它所做的只是复制引用——你最终会得到两个指向同一个对象的引用。如果要创建一个新对象,则必须显式调用构造函数:

object1 = new GsmSignalStrength( object2 );

至于它是否“无用”,这取决于您的应用程序。复制构造函数、clone()方法和您的copyTo方法都完成相同的基本任务。您可以使用构造函数创建一个新对象,或者使用clone(),或者创建一个新对象并使用copyTo它——选择一种方法来做你想做的事并坚持下去。

于 2012-04-11T15:47:10.210 回答
1

我认为你应该只使用克隆,但要小心。Joshua Bloch 的 Effective Java 指出您应该明智地使用 clone,因为它是一个弱接口并且没有提供方法契约来支持该活动。您还依赖于行为良好的超类克隆行为(即,超类使用super#clone而不是使用类构造函数来创建对象(这将创建错误类的实例)。请注意,这是您在您的文件 2 示例- 在非最终类中,您将破坏任何克隆子类。

请注意,您的克隆(和每个超类克隆)应提供所有 ivars 的完整副本。现在请注意,您可能需要对诸如数组和列表之类的东西进行深度复制——也就是说,创建数组的新实例并在您自己的列表中添加元素的新副本。这是一个“深拷贝”,而不是“浅拷贝”。克隆不应与原始对象共享相同的数据(尽管您可能会根据具体情况对此进行辩论)。

另外,我认为复制构造函数的概念没有任何问题,只要它有充分的文档记录您的副本所做的事情(例如,深副本与浅副本)。

您的示例的示例代码是:

public class GSMSignalStrength implements Cloneable {
    ...
    public Object clone() throws CloneNotSupportedException {
        GSMSignalStrength result = (GSMSignalStrength)super.clone();
        result.setValue(this.value);
        result.setAnyOldArray(this.deepCopyMyAnyOldArray());
        ...
    }
    ...
}

希望这可以帮助!

ps 在泛型方面未审查 Cloneable,因此您可以围绕它添加类型安全性。事实上,我从来没有真正实现过可克隆。在过去(Obj-C 世界,我们确实在图形包中做了很多 cop-constructing 并直接与我们的对象图捆绑在一起 - 何时进行深度复制和何时进行浅复制)。五、复杂。

于 2012-04-11T16:07:32.513 回答