Java'da shallow copy (yüzeysel kopyalama), nesnenin yalnızca iç içe nesnelere olan referanslarının kopyalandığı, nesnelerin kendilerinin değil. Bu nedenle, iç içe nesnelerdeki değişiklikler hem kopyada hem de orijinalinde yansıyacaktır. Deep copy (derin kopyalama) tüm iç nesnelerin yeni bağımsız kopyalarının oluşturulmasını ifade eder.
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(); } } // Kullanım Person p1 = new Person("Ivan", new Address("Moscow")); Person p2 = (Person) p1.clone(); p2.address.city = "Petersburg"; System.out.println(p1.address.city); // "Petersburg" yazdırır — yüzeysel kopyalama
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; } }
Derin kopyalama, nesnenin tamamen bağımsız bir kopyasını oluşturmayı sağlar.
Soru: Herhangi bir karmaşık nesnenin garantili derin kopyasını elde etmek için clone() metodunu kullanabilir miyiz?
Cevap: Hayır, standart clone() yalnızca yüzeysel kopyalama yapar (shallow copy). Derin kopyalamak için, iç içe tüm sınıflarda clone() metodunu geçersiz kılmak ve tüm referans alanlarını açıkça klonlamak gerekir. Ayrıca birçok koleksiyon ve standart sınıf derin kopyalamayı desteklememektedir.
Hikaye
Bir kullanıcılar ve onların adresleri koleksiyonu, derin kopyalama olmadan clone() metodu ile kopyalandı. Bir kullanıcının adresi değiştirildiğinde, diğerinin adresi de değişti çünkü referans kopyalanıyordu. Veriler arasında "sızma" oldu.
Hikaye
İç içe koleksiyonlarla karmaşık bir nesnenin serileştirilmesi sırasında, deep copy yerine clone() kullanıldı. Serileştirmeden geri yüklemeyle veriler tutarsız hale geldi ve NPE oluştu.
Hikaye
REST API'de DTO nesneleri varsayılan olarak BeanUtils.copyProperties() ile kopyalandı, bu da bir koleksiyonun istemciler arasında paylaşılmasına neden oldu. Sonuç olarak, kullanıcı başkalarının verilerini görebiliyor ve düzenleyebiliyordu.