W Javie shallow copy (powierzchowne kopiowanie) to kopiowanie obiektu, w którym kopiowane są tylko odniesienia do obiektów zagnieżdżonych, a nie same obiekty. Tak więc zmiany w obiektach zagnieżdżonych wpłyną zarówno na kopię, jak i na oryginał. Deep copy (głębokie kopiowanie) oznacza tworzenie nowych niezależnych kopii wszystkich zagnieżdżonych obiektów.
class Address implements Cloneable { String city; Address(String city) { this.city = city; } protected Object clone() throws CloneNotSupportedException { return super.clone(); } } class Person implements Cloneable { String name; Address address; Person(String name, Address address) { this.name = name; this.address = address; } protected Object clone() throws CloneNotSupportedException { return super.clone(); } } // Użycie Person p1 = new Person("Ivan", new Address("Moskwa")); Person p2 = (Person) p1.clone(); p2.address.city = "Petersburg"; System.out.println(p1.address.city); // Wyświetli "Petersburg" — kopiowanie powierzchowne
class Address implements Cloneable { String city; Address(String city) { this.city = city; } protected Object clone() throws CloneNotSupportedException { return new Address(this.city); } } class Person implements Cloneable { String name; Address address; Person(String name, Address address) { this.name = name; this.address = address; } protected Object clone() throws CloneNotSupportedException { Person cloned = (Person) super.clone(); cloned.address = (Address) address.clone(); return cloned; } }
Głębokie kopiowanie pozwala stworzyć całkowicie niezależną kopię obiektu.
Pytanie: Czy można użyć metody clone() do gwarantowanego głębokiego kopiowania dowolnego skomplikowanego obiektu?
Odpowiedź: Nie, standardowy clone() wykonuje tylko kopiowanie powierzchowne (shallow copy). Aby uzyskać głębokie kopiowanie, należy nadpisać clone() we wszystkich zagnieżdżonych klasach i jawnie klonować wszystkie pola-odniesienia. Ponadto wiele kolekcji i standardowych klas nie obsługuje głębokiego klonowania.
Historia
Kolekcja użytkowników i ich adresów była klonowana metodą clone() bez głębokiego kopiowania. Po zmianie adresu u jednego użytkownika, adres zmienił się również u drugiego, ponieważ kopiowana była referencja. Dane w bazie "popłynęły" między użytkownikami.
Historia
Podczas serializacji skomplikowanego obiektu z zagnieżdżonymi kolekcjami używano clone(), a nie głębokiej kopii. Po przywróceniu z serializacji dane okazały się niespójne i wystąpiły NPE.
Historia
W REST API obiekty DTO były klonowane domyślnie przez BeanUtils.copyProperties(), co prowadziło do podziału tej samej kolekcji między klientami. W wyniku tego użytkownik mógł widzieć i edytować cudze dane.