Что эта копия поля полем сделана Object.clone ()?

В Эффективном Java автор заявляет что:

Если класс реализует Cloneable, метод клона Объекта возвращает копию поля полем объекта; иначе это бросает CloneNotSupportedException.

То, что я хотел бы знать, - то, что он имеет в виду с копией поля полем. Это означает, что, если класс имеет X байты в памяти, он просто скопирует ту часть памяти? Если да, то я могу предположить, что все типы значения исходного класса будут скопированы в новый объект?

class Point implements Cloneable{
    private int x;
    private int y;

    @Override
    public Point clone() {
        return (Point)super.clone();
    }
}

Если, что Object.clone() делает поле полевой копией Point класс, я сказал бы, что не должен буду явно копировать поля x и y, быть, что кода, показанного выше, будет более чем достаточно для создания клона Point класс. Таким образом, следующий бит кода избыточен:

@Override
public Point clone() {
    Point newObj = (Point)super.clone();
    newObj.x = this.x; //redundant
    newObj.y = this.y; //redundant
}

Я прав?

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

12
задан Paŭlo Ebermann 12 August 2011 в 01:28
поделиться

4 ответа

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

class Line implements Cloneable {

    private Point start;
    private Point end;

    public Line() {
        //Careful: This will not happen for the cloned object
        SomeGlobalRegistry.register(this);
    }

    @Override
    public Line clone() {
        //calling super.clone is going to create a shallow copy.
        //If we want a deep copy, we must clone or instantiate
        //the fields ourselves
        Line line = (Line)super.clone();
        //assuming Point is cloneable. Otherwise we will
        //have to instantiate and populate it's fields manually
        line.start = this.start.clone();
        line.end = this.end.clone;
        return line;
    }
}

Также еще одна важная особенность клонирования заключается в том, что конструктор клонированного объекта никогда не вызывается (копируются только поля). Поэтому если конструктор инициализирует внешний объект или регистрирует этот объект в каком-то реестре, то для клонированного объекта этого не произойдет.

Лично я предпочитаю не использовать клонирование в Java. Вместо этого я обычно создаю свои собственные методы "дублирования".

5
ответ дан 2 December 2019 в 21:02
поделиться

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

Для объектов неглубокая копия означает копирование только ссылки. Поэтому в этих случаях обычно требуется глубокая копия. Исключение составляют случаи, когда ссылка указывает на неизменяемый объект. Неизменяемые объекты не могут изменить свое видимое состояние, поэтому их ссылки можно безопасно копировать. Например, это относится к String, Integer, Float, перечислениям (если они не были изменены по ошибке).

1
ответ дан 2 December 2019 в 21:02
поделиться

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

4
ответ дан 2 December 2019 в 21:02
поделиться
newObj.x = this.x; //redundant
newObj.y = this.y; //redundant

это верно - они избыточны, поскольку уже были скопированы методом Object's clone().

Думать об этом как о копировании данных - правильно. Примитивные типы копируются, а ссылки также копируются, чтобы они указывали на один и тот же объект. Например,

class A implements Cloneable {
  Object someObject;
}

A a = new A();
a.someObject = new Object();

A cloneA = (A)a.clone();
assert a.someObject==cloneA.someObject;
4
ответ дан 2 December 2019 в 21:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: