Objectkopie in Java is het proces van het creëren van een nieuw object met dezelfde staat als een bestaand exemplaar. Historisch gezien werd kopieëren relevant vanaf de vroege ontwikkeling van Java, toen de noodzaak ontstond om objecten te dupliceren zonder ze handmatig opnieuw te maken. Java zelf biedt geen universele manier voor objectkopie, maar gebruikt in plaats daarvan het contract clone() en het kopieerconstructorpatroon.
De methode clone() werd geïntroduceerd in de Cloneable interface om een standaardmechanisme voor het klonen van objecten te bieden, maar de implementatie hierover komt met veel nuanceringen en leidt vaak tot bugs.
Het grootste probleem is het ontbreken van echte diepe kopie "out of the box" en de mogelijkheid van onvoorspelbaar gedrag bij oppervlakkig klonen (shallow copy). De kopieerconstructor maakt zowel oppervlakkige als diepe kopie mogelijk, maar vereist expliciete implementatie.
Voor veilige en correcte kopie van complexe objecten is het beter om een kopieerconstructor of fabrieksmethode te gebruiken, terwijl clone() met voorzichtigheid moet worden toegepast — alleen als het object daadwerkelijk geschikt is voor dit contract.
Codevoorbeeld:
// Oppervlakkige kloon via clone() public class Address implements Cloneable { String city; public Address(String city) { this.city = city; } @Override public Address clone() throws CloneNotSupportedException { return (Address) super.clone(); } } public class Person implements Cloneable { String name; Address address; public Person(String name, Address address) { this.name = name; this.address = address; } @Override public Person clone() throws CloneNotSupportedException { Person copy = (Person) super.clone(); copy.address = address.clone(); // diepe kopie van address return copy; } } // Kopieerconstructor public class Person { String name; Address address; public Person(Person other) { this.name = other.name; this.address = new Address(other.address.city); } }
Belangrijke kenmerken:
clone() vereist de implementatie van de Cloneable interface en het overschrijven van de clone methode.Vraag 1: Wat gebeurt er als de klasse Cloneable niet implementeert, wat gebeurt er bij het aanroepen van clone()?
clone() zal CloneNotSupportedException gooien als het object de Cloneable interface niet implementeert.
Vraag 2: Is klonen via clone() standaard diep?
Nee, standaard is het alleen oppervlakkig klonen, alle referenties naar objecten worden als zodanig gekopieerd.
Vraag 3: Is het mogelijk om zonder een kopieerconstructor diepe kloning uit te voeren?
Nee, als u het proces wilt controleren, moet u expliciet de kopie van geneste objecten via de constructor of handmatig in clone() implementeren.
Een ontwikkelaar paste de standaard clone() toe in de Order-klasse met een List<Product>-veld. Hierdoor, bij wijzigingen in de productlijst in de kopie, wijzigden ook de producten in het origineel, wat tot een bug leidde.
Voordelen:
Nadelen:
In het bedrijf implementeren ze een kopieerconstructor voor alle domeinsubjecten en dekten ze het kloningsproces voor complexe geneste objecten aanvullend met tests.
Voordelen:
Nadelen: