Глубокая копия массива объектов - PullRequest
12 голосов
/ 16 октября 2010

Я хочу сделать глубокую копию массива объектов с помощью конструктора.

public class PositionList {
    private Position[] data = new Position[0];

public PositionList(PositionList other, boolean deepCopy) {
        if (deepCopy){
            size=other.getSize();
            data=new Position[other.data.length];
            for (int i=0;i<data.length;i++){
            data[i]=other.data[i];
            }

Однако то, что у меня выше почему-то не работает. У меня есть автоматизированные тесты, которые я запускаю, и они не проходят эти тесты. Таким образом, здесь есть ошибка, что я не уверен, что это такое.

Ответы [ 5 ]

23 голосов
/ 16 октября 2010

То, что вы реализовали, является мелкой копией. Для реализации копии deep необходимо изменить

data[i] = other.data[i];

для некоторой вещи, которая назначает копию из other.data[i] для data[i]. Как вы это сделаете, зависит от класса Position. Возможные альтернативы:

  • конструктор копирования:

    data[i] = new Position(other.data[i]);

  • заводской метод:

    data[i] = createPosition(other.data[i]);

  • клон:

    data[i] = (Position) other.data[i].clone();

Примечания:

  1. Выше предполагается, что конструктор копирования, метод фабрики и метод клона соответственно реализуют "правильный" вид копирования, в зависимости от класса Position; см. ниже.
  2. Подход clone будет работать только в том случае, если Position явно его поддерживает, и это обычно рассматривается как неполноценное решение. Кроме того, вы должны знать, что нативная реализация clone (т.е. метод Object.clone()) делает поверхностную копию.

На самом деле общая проблема реализации глубокого копирования в Java сложна. В случае класса Position можно предположить, что все атрибуты представляют собой примитивные типы (например, целые или двойные), и поэтому копирование с глубоким или поверхностным копированием является спорным. Но если есть ссылочные атрибуты, то вам нужно полагаться на конструктор копирования / метод фабрики / метод клона, чтобы выполнить тот тип копирования, который вам необходим. В каждом случае его необходимо запрограммировать. А в общем случае (где вам приходится иметь дело с циклами) это сложно и требует от каждого класса реализации специальных методов.

Существует еще один потенциальный способ копирования массива объектов. Если объекты в массиве serializable , то вы можете скопировать их, используя ObjectOutputStream и ObjectInputStream serialize, а затем десериализовать массив. Однако:

  • это дорого,
  • это работает, только если объекты (транзитивно) сериализуемы, и
  • значения любых полей transient не будут скопированы.

Копирование с помощью сериализации не рекомендуется. Было бы лучше поддержать клонирование или какой-либо другой метод.

В общем, глубокого копирования лучше избегать в Java.

Наконец, чтобы ответить на ваш вопрос о работах конструктора копирования классов Position, я ожидаю, что это что-то вроде этого:

public class Position {
    private int x;
    private int y;
    ...
    public Position(Position other) {
        this.x = other.x;
        this.y = other.y;
    }
    ...
}

Как говорит @Turtle, в этом нет никакой магии. Вы реализуете конструктор (вручную), который инициализирует его состояние путем копирования из существующего экземпляра.

2 голосов
/ 16 октября 2010

Когда вы говорите:

data[i]=other.data[i];

Вы просто копируете список ссылок (предполагая, что это массив объектов). Если вы хотите сделать глубокую копию, вам нужно использовать new для создания нового экземпляра каждого объекта в массиве.

1 голос
/ 16 октября 2010

Вместо того чтобы сказать:

data[i]=other.data[i]

Вы захотите сделать конструктор копирования для Position (другими словами, конструктор для Position, который принимает другое Position и копирует примитивные данные внутри него) и говорит data[i]=new Position(other.data[i]);

По сути, ваш конструктор "глубокого копирования" PositionList является конструктором копирования, хотя конструктор копирования обычно указывает на глубокое копирование, поэтому параметр deepCopy не нужен.

0 голосов
/ 15 апреля 2018

Вот функция, которую я использую:

function copy(arr) {
  return arr
    .map(x => Object
      .keys(x)
      .reduce((acc, y) => {
        acc[y] = x[y]
        return acc
      }, {}))
}

Работает только с массивами с объектами одного уровня.

0 голосов
/ 06 декабря 2016

Это должно сделать "глубокую" копию

int [] numbers = { 2, 3, 4, 5};

int [] numbersClone = (int[])numbers.clone();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...