In Java, che cos’è una copia superficiale?

java.util.Calendar.clone () restituisce “… un nuovo calendario con le stesse proprietà” e restituisce “una copia superficiale di questo calendario”.

Questo non sembra essere una copia superficiale come risposta qui su SO. Quella domanda è codificata in linguaggio agnostico, Java non sembra seguire la definizione agnostica del linguaggio. Mentre passo attraverso il codice, noto che la struttura e gli elementi vengono copiati in questo nuovo object, più della sola struttura agnostica del linguaggio.

In Java, che cos’è una copia superficiale?

In che cosa differisce da una copia profonda di Java (se esiste)?

Una copia superficiale copia semplicemente i valori dei riferimenti nella class. Una copia profonda copia i valori. dato:

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 

In questo caso la copia superficiale ha lo stesso riferimento ( == ) e la copia profonda ha solo un riferimento equivalente ( .equals() ).

Se viene apportata una modifica al valore di un riferimento superficialmente copiato, la copia riflette tale modifica perché condivide lo stesso riferimento. Se viene apportata una modifica al valore di un riferimento profondamente copiato, la copia non riflette tale modifica poiché non condivide lo stesso riferimento.

C-ism

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

Risultato:

 a is 11 *b is 11 c is 10 

La copia superficiale è solo un insieme di puntatori alle stesse posizioni di memoria. In realtà non crea una copia reale, quindi l’utilizzo della memoria è inferiore.

Nel caso di una copia profonda, viene creata una copia esatta del segmento di memoria e i puntatori sono impostati su nuove posizioni di memoria. Quindi teoricamente il consumo di memoria dovrebbe essere due volte in questo caso.

Una copia superficiale è una copia del puntatore di riferimento all’object, mentre una copia profonda è una copia dell’object stesso. In Java, gli oggetti sono mantenuti sullo sfondo, ciò con cui normalmente interagisci quando si ha a che fare con gli oggetti sono i puntatori. I nomi delle variabili indicano lo spazio di memoria dell’object. Una copia superficiale viene eseguita quando si imposta una variabile uguale a un’altra in questo modo:

 Object B = A; 

È ansible eseguire una copia approfondita ottenendo le proprietà dell’object A e inserendole in un nuovo object B.

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

Ciò influisce sul comportamento del programma in quanto se si esegue una copia superficiale e si esegue un’attività su di essa, ciò influisce su tutte le copie poco profonde dell’object. Se apporti una modifica a una copia profonda, solo quella copia è interessata. Spero che questo sia abbastanza dettagliato per te.

Il documento 1.6 documenta Calendar.clone come “Crea e restituisce una copia di questo object”. Una letterale copia superficiale come specificato da Object.clone non avrebbe alcun senso. Java usa il termine “copia superficiale” in un senso abbastanza tipico.

Sembra essere un errore nella documentazione. Non vedo come tutto ciò che il metodo Calendar.clone di Android soddisfa la definizione tipica (in Java o in altro modo) di una “copia superficiale”.

Dove stai ottenendo questa documentazione?

I documenti ufficiali di Java 6 su java.sun.com hanno semplicemente Calendar.clone () che restituisce una copia dell’object. Nessuna menzione di superficiale.

Più in generale, una copia superficiale in Java è quella in cui si ottiene un nuovo riferimento all’object ma il nuovo object contiene (direttamente o indirettamente) riferimenti ai dati nell’originale.

Per esempio:

 class MyClass{ private List innerList; public MyClass(List list) { innerList = list; } //Some code... public Object clone(){ return new MyClass(innerList); } } 

restituisce una copia superficiale nel suo clone ().

Prima di tutto, Javadoc di ArrayList è in qualche modo sbagliato se stiamo parlando di array monodesmensionali, poiché usa il metodo copyOf in Arrays. Quindi clone () restituisce una copia monodesmensionale, almeno dal 1.5 (non ho testato ulteriormente)! Ecco cosa significa “superficiale” in Java: unidimensionale

Puoi leggere di più qui: http://www.javapractices.com/topic/TopicAction.do?Id=3 . Quindi clone () non è una copia superficiale! Se vuoi una copia veramente superficiale di un array monodesmensionale, fai riferimento a questo:

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

Le matrici in Java sono complicate, anche perché Java fa il pass-by-value, ma i valori degli array sono solo i loro indicatori! D’altra parte questo ci permette di sincronizzare gli oggetti, che è una grande cosa. Tuttavia, ci sono alcuni problemi se si usano array all’interno di array (o ArrayList), perché un clone () dell’array contenitore (o ArrayList) non copierà i loro valori, solo i loro riferimenti! Quindi non dovresti semplicemente mettere array in un array, dovresti solo occuparti di oggetti in un array!

E a volte Javadoc è difficile da capire, quindi prova a provare …

Divertiti!

Una copia superficiale copia semplicemente il riferimento all’object nel riferimento di destinazione. Non crea un nuovo object sull’heap. Per impostazione predefinita, Java esegue la clonazione superficiale utilizzando la funzione clone ().

Per ottenere un nuovo object sull’heap, è necessario eseguire una clonazione profonda che può essere implementata dalla serializzazione e dalla de-serializzazione.

In una copia superficiale, l’object clone ha una copia dei valori primitivi ma i riferimenti agli oggetti si riferiscono agli stessi oggetti della copia originale. Le copie poco profonde hanno uno svantaggio significativo, l’object clonato e la copia originale si riferiscono allo stesso object di indirizzo. Qualsiasi modifica che l’object clonato rende nell’object indirizzo si rifletterà anche nella copia originale, che è un comportamento indesiderato. Quello che volevamo veramente è due copie separate dell’object utente. La copia profonda viene in nostro soccorso per questo tipo di situazione.

Copiando in profondità i cloni non solo i valori primitivi, crea anche copie di riferimenti a oggetti.

Puoi dare un’occhiata all’esempio di lavoro su questo qui: https://codingninjaonline.com/2017/11/09/deep-vs-shallow-copy/