Возвращенная модификация объекта java - PullRequest
0 голосов
/ 29 марта 2012

Некоторые вопросы по основам 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 ]

2 голосов
/ 29 марта 2012

Метод getNode() в классе DS возвращает ссылку на узел, сохраненный в nodeList. Таким образом, если ваш класс Node может быть видоизменен (с помощью методов установки или прямого доступа к его полям), то да, ваш код в test1 изменит базовую (и теперь совместно используемую) ссылку на узел.

Если вы хотите «отключить» возвращенный узел от узла в вашем хранилище данных, тогда вы можете клонировать сначала. Класс вашего узла должен будет реализовать Cloneable и переопределить метод clone(). Если у вас есть только примитивы в Node, то вы можете просто сделать:

public Object clone()
{
  return super.clone();
}

Если у вас есть другие объекты в Node, то операция клонирования по умолчанию сделает только поверхностную копию , и вам нужно будет сделать ваш метод клонирования более расширенным, чтобы он делал глубокие копии . Из Javadoc для Object.clone ():

По соглашению, объект, возвращаемый этим методом, должен быть независимым от этого объекта (который клонируется). Для достижения этой независимости может потребоваться изменить одно или несколько полей объекта, возвращаемого super.clone, перед его возвратом. Как правило, это означает копирование любых изменяемых объектов, которые составляют внутреннюю «глубокую структуру» клонируемого объекта, и замену ссылок на эти объекты ссылками на копии. Если класс содержит только примитивные поля или ссылки на неизменяемые объекты, то обычно бывает так, что нет необходимости изменять поля в объекте, возвращенном super.clone.

Изменение в вашем классе DS будет:

public Node getNode(int index){
    return (Node) nodeList.get(index).clone();
}
1 голос
/ 29 марта 2012

Да, изменение node в test1() изменит объект, который находится в списке ds.Это потому, что это ссылка на тот же объект.

Если вы хотите изменить node, не затрагивая оригинал, вам нужно сделать копию - например, сделать new Node(), а затем скопировать все поля изстарый на новый.Вы также можете реализовать интерфейс Cloneable и использовать метод clone(), предоставляемый классом Object.Или предоставьте Node конструктор, который принимает в качестве аргумента другой Node и копирует свои данные.

0 голосов
/ 29 марта 2012

Как уже упоминали другие, ответ - Да.

Еще не упомянутая опция - сделать объект Node неизменным .

0 голосов
/ 29 марта 2012

Да.Вы просто получите ссылку на (тот же) объект 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 безопасно предоставляет объекты вызывающей стороне иВаш класс защищен от случайного изменения его состояния (т. е. полей).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...