返回对象修改java

时间:2012-03-29 01:25:06

标签: java reference

关于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?
}

提前致谢。

4 个答案:

答案 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