2009-07-24 6 views
37

java.util.Calendar.clone() возвращает «... новый календарь с теми же свойствами» и возвращает «мелкую копию этого Календаря».В Java, что такое мелкая копия?

Это не выглядит мелкой копией, как указано here. Этот вопрос отмечен language-agnostic, Java, похоже, не соответствует языковому агностическому определению. Когда я просматриваю код, я замечаю, что структура и элементы копируются на этот новый объект, больше, чем только агностическая структура языка.

В Java, что такое мелкая копия?

Как он отличается от глубокой копии Java (если таковой существует)?

+1

Okay. Похоже, что вынос заключается в том, что явная мелкая/глубокая копия такая же, как и остальные миры программирования, это просто документация для android 1.5 java.util.Calendar.clone(), это просто неправильно. clone() - это глубокая копия, а не мелкая копия. – Will

+0

С первого взгляда все поля кажутся типами значений, поэтому, будь то мелкие или глубокие, в этом случае не будет иметь значения. –

ответ

60

Неглубокая копия просто копирует значения ссылок в классе. Глубокая копия копирует значения.Дано:

class Foo { 
    private Bar myBar; 
    ... 
    public Foo shallowCopy() { 
    Foo newFoo = new Foo(); 
    newFoo.myBar = myBar; 
    return newFoo; 
    } 

    public Foo deepCopy() { 
    Foo newFoo = new Foo(); 
    newFoo.myBar = myBar.clone(); //or new Bar(myBar) or myBar.deepCopy or ... 
    return newFoo; 
    } 
} 

Foo myFoo = new Foo(); 
Foo sFoo = myFoo.shallowCopy(); 
Foo dFoo = myFoo.deepCopy(); 

myFoo.myBar == sFoo.myBar => true 
myFoo.myBar.equals(sFoo.myBar) => true 
myFoo.myBar == dFoo.myBar => **false** 
myFoo.myBar.equals(dFoo.myBar) => true 

В этом случае поверхностное копирование имеет ту же ссылку (==) и глубокая копия имеет только эквивалентную ссылку (.equals()).

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

C-изма

int a = 10; //init 
int& b = a; //shallow - copies REFERENCE 
int c = a; //deep - copies VALUE 
++a; 

Результат:

a is 11 
*b is 11 
c is 10 
+0

Что произойдет, если вы внесете изменения в мелкую копию? Изменит ли он мелко скопированную ссылку? –

+2

Зависит. 'newFoo.bar = newBar' будет только изменять' '' '' 'NewFoo''''''''''''. Но 'newFoo.bar.avalue = 1' изменит оба. – KitsuneYMG

3

Документ документов документа 1.6 Calendar.clone как «Создает и возвращает копию этого объекта». Буквальная мелкая копия, указанная в Object.clone, не имеет никакого смысла. Java использует термин «мелкая копия» в довольно типичном смысле.

1

Где вы получаете эту документацию?

Официальные документы Java 6 на java.sun.com просто имеют Calendar.clone(), возвращая копию объекта. Не упоминается мелкий.

В общем случае мелкая копия на Java является той, где вы получаете новую ссылку на объект, но новый объект держит (прямо или косвенно) ссылки на данные в оригинале.

Например:

class MyClass{ 
    private List<Integer> innerList; 

    public MyClass(List<Integer> list) { innerList = list; } 

    //Some code... 

    public Object clone(){ 
    return new MyClass(innerList); 
    } 
} 

возвращает неполную копию в клоне().

+0

Документация взята из последней версии Android 1.5 SDK – Will

+0

Примечание 'clone()' не следует вызывать конструктор в соответствии с 'Object.clone()' spec. – notnoop

+1

Да, да, технически вы должны получить Object из super.clone(); бросьте его в MyClass, а затем задайте поля волшебным образом. Это гораздо больше кода, чтобы показать это, и суть вопроса - это мелкое/глубокое различие. –

9

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

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

+4

Это вопрос Java, а не вопрос C/C++, поэтому разговоры о сегментах памяти вводят в заблуждение. –

+1

Не думайте, что много высокого уровня. На любом языке вы имеете дело с физическим оборудованием, таким как память и процессор. Даже мы не используем alloc, mallocs не думают, что мы не используем память в Java. –

+1

Relax, Stephen ... для людей, пришедших с C/C++ фона, ответ Чатуранги на самом деле помогает. Хорошо иметь разные взгляды на одну и ту же проблему. – cjcela

4

Неглубокая копия является копией ссылочного указателя на объект, тогда как глубокая копия является копией самого объекта. В Java объекты хранятся в фоновом режиме, то, что вы обычно взаимодействуете при работе с объектами, - это указатели. Имена переменных указывают на пространство памяти объекта. Мелкий копия сделана, когда вы установите одну переменную, равную другой, как так:

Object B = A; 

глубокая копия может быть сделана путем получения свойств объекта А и положить их в новый объект B.

Object B = new Object(A.getProperty1(), A.getProperty2()...); 

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

+2

это не правильно. если вы делаете Object B = A, вы сглаживаете A. Это не мелкая копия, скорее это просто задание. если вы выполняете A.clone() и назначаете его B, это будет правильное определение мелкой копии. – Inquisitive

2

Это, кажется, ошибка в документации. Я не вижу, как все, что делает этот метод Android Calendar.clone, соответствует типичному определению (на Java или иначе) «мелкой копии».

0

Прежде всего, Javadoc из ArrayList несколько ошибочен, если мы говорим об одномерных массивах, так как он использует метод copyOf в массивах. Итак, clone() возвращает одномерную копию, по крайней мере с 1,5 (я еще не тестировал)! Итак, это то, что «неглубоко» означает в Java: одномерный

Вы можете прочитать больше здесь: http://www.javapractices.com/topic/TopicAction.do?Id=3. Таким образом, clone() не является мелкой копией! Если вы хотите реальную неполную копию одномерного массива, просто ссылаться на него:

Array a = new Array(); 
Array b = a;     //a is only a shallow copy, nice for synchronisation 

Массивы в Java являются хитрыми, а также потому, что Java делает передачу по значению, но значения массивов только их указатели ! С другой стороны, это позволяет нам синхронизировать объекты, что очень важно. Тем не менее, есть некоторые проблемы, если вы используете массивы в массивах (или ArrayLists), потому что clone() из массива контейнеров (или ArrayList) не будет копировать их значения, а только их ссылки! Таким образом, вы просто не должны помещать массивы в массив, вы должны иметь дело только с объектами в массиве!

И Javadoc трудно иногда понять, чтобы дать испытания попробовать ...

Удачи!

0

Неглубокая копия просто копирует ссылку на объект в целевую ссылку. Он не создает новый объект в куче. По умолчанию Java выполняет мелкое клонирование с использованием функции clone().

Чтобы получить новый объект в куче, необходимо выполнить глубокое клонирование, которое может быть реализовано путем сериализации и де-сериализации.

0

В неглубокой копии объект клона имеет копию примитивных значений, но ссылки на объекты относятся к тем же объектам, что и исходная копия. Мелкие копии имеют значительный недостаток, клонированный объект и оригинальную копию относятся к одному и тому же адресу. Любое изменение, которое клонированный объект делает в объекте адреса, также будет отражено в оригинальной копии, что является нежелательным поведением. Нам действительно нужны две отдельные копии пользовательского объекта. Глубокое копирование приходит на помощь для такого рода ситуаций.

Глубокое копирование клонов не только примитивных значений, но и создает копии ссылок на объекты.

Вы можете посмотреть на рабочий пример на это в здесь: https://codingninjaonline.com/2017/11/09/deep-vs-shallow-copy/