Introducere
atunci Când vrem să copiați un obiect în Java, există două posibilități de care avem nevoie să ia în considerare — o copie superficială și o copie profundă.
copia superficială este abordarea atunci când copiem numai valorile câmpului și, prin urmare, copia poate depinde de obiectul original. În abordarea deep copy, ne asigurăm că toate obiectele din arbore sunt copiate profund, astfel încât copia să nu depindă de niciun obiect existent anterior care s-ar putea schimba vreodată.,în acest articol, vom compara aceste două abordări și vom învăța patru metode pentru a implementa copia profundă.
Lectură suplimentară:
Java Copy Constructor
copierea seturilor în Java
Copierea unui HashMap în Java
Maven de Configurare
Vom folosi trei Maven dependențe — Gson, Jackson, și Apache Commons Lang — pentru a testa diferite moduri de a efectua o copie profundă.
să adăugăm aceste dependențe la pom-ul nostru.xml:
cele mai recente versiuni ale Gson, Jackson și Apache Commons Lang pot fi găsite pe Maven Central.,
Model
Pentru a compara diferite metode pentru a copia obiecte Java, vom avea nevoie de două clase pentru a lucra la:
class Address { private String street; private String city; private String country; // standard constructors, getters and setters}
class User { private String firstName; private String lastName; private Address address; // standard constructors, getters and setters}
Copie Superficială
O copie superficială este una în care ne-am doar copia valorile din câmpurile de la un obiect la altul:
În acest caz, pm != shallowCopy, ceea ce înseamnă că sunt obiecte diferite, dar problema este că atunci când schimbăm oricare dintre proprietățile adresei originale, aceasta va afecta și adresa shallowCopy.,
Nu ne-am deranja dacă Adresa ar fi imuabilă, dar nu este:
copie profundă
o copie profundă este o alternativă care rezolvă această problemă. Avantajul său este că cel puțin fiecare obiect mutabil din graficul obiectului este copiat recursiv.deoarece copia nu depinde de niciun obiect mutabil care a fost creat anterior, nu va fi modificat accidental, așa cum am văzut cu copia superficială.
în secțiunile următoare, vom afișa mai multe implementări de copiere profundă și vom demonstra acest avantaj.
5. 1., Constructor de copiere
prima implementare vom pune în aplicare se bazează pe copia constructori:
public Address(Address that) { this(that.getStreet(), that.getCity(), that.getCountry());}
public User(User that) { this(that.getFirstName(), that.getLastName(), new Address(that.getAddress()));}
În cele de mai sus implementării copie profundă, nu ne-am creat noi Siruri de caractere noastre constructor de copiere pentru că Șirul este o imuabil clasa.ca urmare, acestea nu pot fi modificate accidental. Să vedem dacă funcționează:
5.2. Interfață Cloneable
a doua implementare se bazează pe metoda clona moștenit de la obiect. Este protejat, dar trebuie să-l suprascrie ca public.,
Vom adăuga, de asemenea, un marker interfata Cloneable, la clase pentru a indica faptul că clasele sunt de fapt cloneable.
să adăugăm metoda clone() la clasa de adrese:
și acum să implementăm clone() pentru clasa utilizator:
rețineți că super.clone () call returnează o copie superficială a unui obiect, dar setăm copii profunde ale câmpurilor mutabile manual, astfel încât rezultatul este corect:
biblioteci externe
exemplele de mai sus arată ușor, dar uneori nu se aplică ca soluție atunci când nu putem adăuga un constructor suplimentar sau suprascrie metoda clonei.,
Acest lucru se poate întâmpla atunci când nu deținem codul sau când graficul obiect este atât de complicat încât nu am termina proiectul la timp dacă ne-am concentra pe scrierea de constructori suplimentari sau implementarea metodei clone pe toate clasele din graficul obiect.
atunci ce? În acest caz, putem folosi o bibliotecă externă. Pentru a obține o copie profundă, putem serializa un obiect și apoi îl putem deserializa la un obiect nou.să ne uităm la câteva exemple.
6. 1., Apache Commons Lang
Apache Commons Lang a SerializationUtils#clona, care efectuează o copie profundă atunci când toate clasele în obiect grafic implementeze interfata Serializable.
dacă metoda întâlnește o clasă care nu este serializabilă, va eșua și va arunca o SerializationException necontrolată.din acest motiv, trebuie să adăugăm interfața Serializabilă la clasele noastre:
6.2. Serializarea JSON cu Gson
un alt mod de a serializa este de a utiliza serializarea JSON. Gson este o bibliotecă care este folosit pentru a converti obiecte în JSON și vice-versa.,spre deosebire de Apache Commons Lang, GSON nu are nevoie de interfața Serializabilă pentru a face conversiile.
Să aruncăm o privire rapidă la un exemplu:
6.3. Serializarea JSON cu Jackson
Jackson este o altă bibliotecă care acceptă serializarea JSON. Această implementare va fi foarte asemănătoare cu cea care utilizează Gson, dar trebuie să adăugăm constructorul implicit la clasele noastre.
Să vedem un exemplu:
concluzie
ce implementare ar trebui să folosim atunci când facem o copie profundă?, Decizia finală va depinde adesea de clasele pe care le vom copia și dacă deținem clasele din graficul obiectului.ca întotdeauna, probele complete de cod pentru acest tutorial pot fi găsite pe GitHub.
începeți cu arc 5 și Primăvara Boot 2, prin Învețe Primăvară curs:
>> CHECK OUT CURS