复制构造函数在这里没用?

时间:2012-04-11 15:33:09

标签: java

考虑以下情况:

我为嵌入式(调制解调器)设备编写了一个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“StateMachine”:

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

2 个答案:

答案 0 :(得分: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 - 选择一种方法来执行您想要的操作并坚持使用它。

答案 1 :(得分:1)

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

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

此外,我认为复制构造函数概念没有任何问题,只要它能够很好地记录您的副本的作用(例如深拷贝和浅拷贝)。

示例的示例代码为:

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

希望这有帮助!

P.S。在泛型方面没有审查Cloneable,因此您可以在其周围添加类型安全性。事实上,我从来没有真正实现过克隆。在过去(Obj-C世界,我们确实在图形包中进行了很多警察构建,并且与我们的对象图结合在一起 - 何时深入,何时进行浅拷贝)。 V.complicated。