关于java基础知识的一些问题, 下面的函数返回一个Node类型的对象
class DS{
public Node getNode(int index){
return nodeList.get(index);
}
}
public void test1(){
DS ds = new DS();
Node node = ds.getNode(3);
// will the change in node variable(of test1()) change the actual Node object in ds?
// Is there a simple way to create a copy to prevent source node's data modification?
}
提前致谢。
答案 0 :(得分:2)
DS类上的getNode()
方法将引用返回到nodeList
中存储的节点。因此,如果您的Node
类可以变异(通过setter方法或直接访问其字段),那么,test1
中的代码将更改基础(现在共享)节点引用。< / p>
如果要从数据存储区中的节点“断开”返回的节点,则可以先clone它。您的节点类需要实现Cloneable
并覆盖clone()
方法。如果Node中只有原语,那么你可以简单地执行:
public Object clone()
{
return super.clone();
}
如果Node中有其他对象,则默认克隆操作只会生成浅拷贝,并且您需要使克隆方法更广泛,以便它使深拷贝。从Javadoc for Object.clone():
按照惯例,此方法返回的对象应独立于此对象(正在克隆)。要实现此独立性,可能需要在返回之前修改super.clone返回的对象的一个或多个字段。通常,这意味着复制包含被克隆对象的内部“深层结构”的任何可变对象,并使用对副本的引用替换对这些对象的引用。如果一个类只包含原始字段或对不可变对象的引用,那么通常情况下,super.clone返回的对象中的任何字段都不需要修改。
您的DS类的更改将是:
public Node getNode(int index){
return (Node) nodeList.get(index).clone();
}
答案 1 :(得分:1)
是的,修改node
中的test1()
会修改ds
列表中的对象。那是因为它是对同一个对象的引用。
如果要在不影响原件的情况下修改node
,则需要制作副本 - 例如,执行new Node()
,然后将旧字段中的所有字段复制到新字段。您还可以实现Cloneable
接口并使用clone()
类提供的Object
方法。或者给Node
一个构造函数,该构造函数将另一个Node
作为参数并复制其数据。
答案 2 :(得分:0)
是。您只需获得引用到(相同)Node对象。对它做出的任何更改都会反映在任何地方(尽管存在线程问题)。
要返回Node的副本,请执行以下操作:
创建“复制构造函数”:
public Node(Node node) {
// Copy all the fields across
this.field1 = node.field1;
this.field2 = node.field2;
// etc
}
从您的方法中,使用复制构造函数返回一个副本:
public Node getNode(int index){
return new Node(nodeList.get(index));
}
此代码模式称为“安全发布” - 您的API可以安全地向调用者提供对象,并且您的类可以安全地避免意外修改其状态(即字段)。
答案 3 :(得分:0)
正如其他人所说,答案是肯定的。
尚未提及的选项是创建Node对象immutable。