Глубокая копия массива объектов

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

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];
            }

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

Ответ 1

То, что вы внедрили, - это мелкая копия. Чтобы выполнить копию глубокой, вы должны изменение

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

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

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

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

  • a factory метод:

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

  • клон:

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

Примечания:

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

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

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

  • Это дорого,
  • он работает только в том случае, если объекты (транзитно) сериализуемы и
  • значения любых полей 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

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

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

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

Ответ 3

Вместо того, чтобы говорить:

data[i]=other.data[i]

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

В основном ваш конструктор "глубокой копии" PositionList является конструктором копирования, хотя конструктор копирования имеет тенденцию указывать глубокую копию, поэтому параметр deepCopy не нужен.

Ответ 4

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

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

int [] numbersClone = (int[])numbers.clone();