考虑以下情况:
我为嵌入式(调制解调器)设备编写了一个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;
}
}
答案 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。