İçerikler :

clone() Yöntemi Clone() Yöntemi Sadece Nesnenin Kendisini Kop.. Cloneable Deep Copy -Deep Clone - Derin Kopyalama Java'da Apache Lang Kütüphanesi ile Deep Clon.. Java'da Basit Bir Clone Örneği Java'da clone Yönteminin Deep Clone Yapmadığı.. Java'da clone Yöntemleri ile Yapılan Basit Bi.. Java'da JSON Kullanarak Deep Clone Yapan Örne.. Java'da Serileştirme İle Deep Clone Yapan Örn.. Shallow Copy - Shallow Clone- Sığ Kopyalama

Bu Sayfayı Paylaş:

Kavram

clone() Yöntemi

Tanım: Object sınıfında protected olarak bulunan, nesnelerin clone yapılması (kopyasının çıkarılması) için kullanılan native method (yöntem). Bir sınıf Cloneable interface'ni implement ettikten sonra clone() yöntemini override ederse o sınıftan yaratılan tüm nesneler clone alınabilir (kopyalanabilir) hale gelir

Kavram

Cloneable

Tanım: Java'da bir sınıftan yaratılan nesnelerin kopyalanabilir (clone alınabilir) olması için sınıfın implement etmesi gerekli olan interfaces. Herhangi bir method (yöntem) içermez.

Örnek

Java'da Basit Bir Clone Örneği

Bu örnekte basit bir sınıfı kopyası alınabilir (clone) haline getirip kopyasını alıyoruz.
Test sınıfını kopyası alınabilir hale getiriyoruz. Bunun için Cloneable interface'ni implement ettikten sonra clone() yöntemini override ediyoruz:
public class Test implements Cloneable {
	
	private int no;
	private String name;
	
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
}
Bu sınıfı kullanarak aşağıdaki gibi bir uygulama ile kopyasını alıyoruz ve özelliklerini değiştiriyoruz :
public class CloneTestApp {
	
	public static void main(String[] args) {
		
		Test t=new Test();
		t.setNo(1);
		t.setName("Tester");
		
		try {
			Test t2=(Test)t.clone();
			
			t2.setNo(2);
			t2.setName("Tester2");
			
			System.out.println("Orjinal:"+t.getNo()+","+t.getName());
			System.out.println("Kopya:"+t2.getNo()+","+t2.getName());
			
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		
	}
}
Uygulamayı çalıştırdığımızda aşağıdaki gibi bir çıktı vermektedir :
Orjinal:1,Tester
Kopya:2,Tester2
Görüldüğü gibi kopyası alınan nesnede değişiklik yaptığımızda asıl olan nesnede bir değişiklik olmamıştır.
Eğer Test sınıfı Cloneable interface'ni implement etmezse aşağıdaki gibi exception alınır:
java.lang.CloneNotSupportedException: com.fibiler.clone.Test
	at java.lang.Object.clone(Native Method)
	at com.fibiler.clone.Test.clone(Test.java:23)
	at com.fibiler.clone.CloneTestApp.main(CloneTestApp.java:12)
Eğer clone() ile değilde atama yoluyla ikinci bir nesne yaratsaydık örnek aşağıdaki gibi olurdu :
public class CloneTestApp2 {
	
	public static void main(String[] args) {
		
		Test t=new Test();
		t.setNo(1);
		t.setName("Tester");
		
		Test t2=t;
		
		t2.setNo(2);
		t2.setName("Tester2");
		
		System.out.println("Orjinal:"+t.getNo()+","+t.getName());
		System.out.println("Kopya:"+t2.getNo()+","+t2.getName());	
		
	}
}
Bu uygulamayı çalıştırdığımızda aşağıdaki gibi çıktı üretir :
Orjinal:2,Tester2
Kopya:2,Tester2

Görüldüğü gibi t2 nesnesinde yapılan değişiklikler t nesnesini de değiştirmiştir. Çünkü Test t2=t; şeklindeki atamalarda aslında iki değişken de aynı nesnesiyi göstermektedir.
Sonuç olarak kopyalamanın amacı yeni nesnede yapılan değişikliklerin asıl nesneyi değiştirmesini istememektir.

İpucu

Clone() Yöntemi Sadece Nesnenin Kendisini Kopyalar

Java'da Object sınıfınındaki clone() yöntemi ile kopyalama (clone alınma) yapıldığında sadece nesnenin (object) kopyası alınır. Eğer o nesne, başka nesneleri (yani basit tip değil class tipinde alanları) içeriyorsa o nesnelerin kopyası alınmaz. Yani kopya üzerindeki class tipindeki alanlarda bir değişiklik yapılırsa hem asıl hem de kopya nesnesinde değişiklik yapılmış olunur. Bu tür derin olmayan kopyalama (clone) sürecine shallow copy/clone (sığ kopya) adı verilir. Bir nesneyi alt nesneleri ve onların da alt nesneleri varsa tümünü birden kopyalama işlemine ise deep copy/clone (derin kopya) adı verilir ve standart Java'da bu şekilde bir deep copy desteği bulunmamaktadır.

Kavram

Shallow Copy - Shallow Clone- Sığ Kopyalama

Tanım: Java'da bir nesnenin clone() yöntemiyle kopyalandığında sadece sınıfın basit tiplerinin kopyalanması, class tipindeki alanların ise refransların kopyalanması şeklinde yapılan kopyalama. Eğer bir sınıf kopyalandığında tüm alanlardaki nesnelerin de kopyalanması isteniyor ise buna deep clone (derin kopya) adı verilir. Standart Java sürümünde deep copy içinde doğrudan bir destek bulunmaz.

Kavram

Deep Copy -Deep Clone - Derin Kopyalama

Tanım: Bir nesne kopyalandığında alt nesnelerinde kopyalanmasını sağlayan kopyalama yöntemi. Standart Java sürümünde deep copy içinde doğrudan bir destek bulunmamaktadır. Object sınıfındaki clone yöntemi sadece shallow (sığ) kopya yapmaktadır

Örnek

Java'da clone Yönteminin Deep Clone Yapmadığını Gösteren Bir Örnek

Java'da bir object clone() yöntemi ile clone'u (kopya) alınabilir. Ancak bu kopya işlemi sadece nesnenin kopyasını alır. Nesnenin sahip olduğu class tipindeki nesnelerin koypasını almaz. Aşağıdaki örnekler bunu göstermektedir. Test sınıfını kopyası alınabilir hale getiriyoruz. Bunun için Cloneable interface'ni implement ettikten sonra clone() yöntemini override ediyoruz:
public class Test implements Cloneable {
	
	private int no;
	private String name;
	
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
}
Bu test sınıfını içeren bir sınıf yapıyoruz:
public class TestDeep implements Cloneable {
	
	private int no;
	private Test test;

	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public Test getTest() {
		return test;
	}
	public void setTest(Test test) {
		this.test = test;
	}
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
	
}
Şimdi bir uygulama yapıp TestDeep sınıfını clone() yöntemini çağırıyoruz ve içerisindeki test nesnesini değiştiriyoruz:
public class DeepCloneTestApp {
	
	public static void main(String[] args) {
		
		Test t=new Test();
		t.setNo(1);
		t.setName("Tester");
		
		TestDeep parent=new TestDeep();
		parent.setNo(100);
		parent.setTest(t);
		
		try {
			TestDeep t2=(TestDeep)parent.clone();
			
			t2.setNo(1283);
			t2.getTest().setNo(1453);
			t2.getTest().setName("Deep");
			
			System.out.println("Orjinal:"+t.getNo()+","+t.getName());
			System.out.println("Orjinal Deep:"+t2.getNo());
			System.out.println("Kopya Deep:"+t2.getTest().getNo()+","
					+t2.getTest().getName());
			
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		
	}
}
Uygulama aşağıdaki çıktıyı verir :
Orjinal:1453,Deep
Orjinal Deep:1283
Kopya Deep:1453,Deep
Dikkat edilir ise aşağıdaki gibi yapılan değişiklikler t nesnesini de değiştirmiştir.
t2.getTest().setNo(1453);
t2.getTest().setName("Deep");
Bu nedenle t nesnesinin değerleri de 1453 ve Deep olmuştur. Sonuç olarak TestDeep sınıfının nesnesi t2 kopyalandığında içindeki t nesnesi kopyalanmamıştır.

Örnek

Java'da clone Yöntemleri ile Yapılan Basit Bir Deep Clone Gösteren Bir Örnek

Java'da bir object clone() yöntemi ile clone'u (kopya) alınabilir. Ancak bu kopya işlemi sadece nesnenin kopyasını alır. Nesnenin sahip olduğu class tipindeki nesnelerin koypasını almaz. Ancak ana sınıf içinde tüm sahip olan sınıflar için ayrı clone() yöntemi çağrılabilir.
Aşağıdaki gibi bir test sınıfı olsun :
public class Test implements Cloneable {
	
	private int no;
	private String name;
	
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
}
Bu test sınıfını kullanan bir ana sınıfı aşağıdaki gibi yapabiliriz :
public class TestDeep implements Cloneable {
	
	private int no;
	private Test test;
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public Test getTest() {
		return test;
	}
	public void setTest(Test test) {
		this.test = test;
	}
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		
		TestDeep testDeep=(TestDeep)super.clone();
		
		Test testClone=(Test)testDeep.getTest().clone();
		
		testDeep.setTest(testClone);
		
		return testDeep;
	}
	
}
clone() yönteminde TestDeep kendisinin kopyaladıktan sonra kendisi içindeki test nesnesini de kopyalayıp set etmektedir. Bu şekilde TestDeep kopyalandığında test nesnesi de kopyalanmış olacaktır. Aşağıdaki gibi bir uygulama yapalım :
public class DeepCloneTester {
	
	public static void main(String[] args) {
		
		Test t=new Test();
		t.setNo(1);
		t.setName("Tester");
		
		TestDeep parent=new TestDeep();
		parent.setNo(100);
		parent.setTest(t);
		
		try {
			TestDeep t2=(TestDeep)parent.clone();
			
			t2.setNo(1283);
			t2.getTest().setNo(1453);
			t2.getTest().setName("Deep");
			
			System.out.println("Orjinal:"+t.getNo()+","+t.getName());
			System.out.println("Orjinal Deep:"+t2.getNo());
			System.out.println("Kopya Deep:"+t2.getTest().getNo()+","
					+t2.getTest().getName());
			
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		
	}
}
Bu uygulamayı çalıştırdığımızda aşağıdaki gibi bir çıktı üretecektir :
Orjinal:1,Tester
Orjinal Deep:1283
Kopya Deep:1453,Deep
Görüldüğü gibi t1 içindeki Test tipindeki nesne değiştirlmesine rağmen orjinal nesne değişmemiştir.
t2.getTest().setNo(1453);
t2.getTest().setName("Deep");

Sonuç olarak bir sınıf kendi sınıfı içindeki nesneleri klonlayarak deep clone (derin kopyalama) yapabilir. Ancak burada kullanılan tüm nesneler de kendi clone() yöntemlerinde aynı şekilde geliştirme yapmalıdır. Örneğin Test nesnesinde başka bir nesne olsaydı ve o klonlanmasaydı o nesnenin refansı kullanılacaktı ve kopyada değiştirildiği an orjinal nesne de değişmiş olacaktı. Bu nedenle çok fazla nesne yapısı olan bir sınıfın tam bir derin kopyalama yapılması için her sınıfın clone() yöntemini doğru bir şekilde yazmış olması gerekmektedir.

Örnek

Java'da Serileştirme İle Deep Clone Yapan Örnek

Java'da bir object clone() yöntemi ile clone'u (kopya) alınabilir. Ancak bu kopya işlemi sadece nesnenin kopyasını alır. Nesnenin sahip olduğu class tipindeki nesnelerin koypasını almaz. Bunun için bir nesne serileştirilebilir ve sonradan tekrar geri serileştirilebilir. Bu şekilde tamamen değerleri aynı olan ama farklı nesnelerden oluşmuş bir kopya elde edilmiş olunur. Bu yöntemde tüm sınıfların serileştirilebilir (Serializable interface'nin implement etmesi) gerekir. Cloneable interfaces'i implement edilmesine gerek yoktur. Aşağıdaki gibi bir test sınıfı olsun :
import java.io.Serializable;

public class Test implements Serializable
{
	
	private int no;
	private String name;
	
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}

}
Bu test sınıfını kullanan bir ana sınıfı aşağıdaki gibi yapabiliriz :
import java.io.Serializable;

public class TestDeep implements Serializable {
	
	private int no;
	private Test test;

	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public Test getTest() {
		return test;
	}
	public void setTest(Test test) {
		this.test = test;
	}
	
}
Aşağıdaki gibi bir uygulama yapalım :
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class DeepCloneTestObjectStream {
	
	public static void main(String[] args) {
		
		Test t=new Test();
		t.setNo(1);
		t.setName("Tester");
		
		TestDeep parent=new TestDeep();
		parent.setNo(100);
		parent.setTest(t);
		
		try {
			ByteArrayOutputStream bo = new ByteArrayOutputStream();
			ObjectOutputStream o = new ObjectOutputStream(bo);
			o.writeObject(parent);
				
			ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
			ObjectInputStream i = new ObjectInputStream(bi);
				
			TestDeep t2 = (TestDeep)i.readObject();
			
			t2.setNo(1283);
			t2.getTest().setNo(1453);
			t2.getTest().setName("Deep");
			
			System.out.println("Orjinal:"+t.getNo()+","+t.getName());
			System.out.println("Orjinal Deep:"+t2.getNo());
			System.out.println("Kopya Deep:"+t2.getTest().getNo()+","
					+t2.getTest().getName());
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
Bu uygulamayı çalıştırdığımızda aşağıdaki gibi bir çıktı üretecektir :
Orjinal:1,Tester
Orjinal Deep:1283
Kopya Deep:1453,Deep
Görüldüğü gibi t nesnesi değiştirilmesine rağmen orjinal nesne değişmemiştir.
t2.getTest().setNo(1453);
t2.getTest().setName("Deep");
Sonuç olarak bir nesneyi içindeki nesnelerin hepsini en alttaki nesnelere gidecek şekilde içerecek şekilde kopyalamak için serileştirme özelliğ kullanılabilir. Ancak nesnelerin tümü Serializable olmalıdır.

Örnek

Java'da Apache Lang Kütüphanesi ile Deep Clone Yapan Bir Örnek

Java'da bir object clone() yöntemi ile clone'u (kopya) alınabilir. Ancak bu kopya işlemi sadece nesnenin kopyasını alır. Nesnenin sahip olduğu class tipindeki nesnelerin koypasını almaz. Bunun için Apache Lang kütüphanesindeki SerializationUtils sınıfındaki clone() yöntemi kullanılabilir. SerializationUtils yöntemi ile bir sınıfın clone yapılabilmesi için tüm nesnelerin Serializable interface'nin implement etmesi gerekir. Cloneable interfaces'i implement edilmesine gerek yoktur. Aşağıdaki gibi bir test sınıfı olsun :
import java.io.Serializable;

public class Test implements Serializable
{
	
	private int no;
	private String name;
	
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}

}
Bu test sınıfını kullanan bir ana sınıfı aşağıdaki gibi yapabiliriz :
import java.io.Serializable;

public class TestDeep implements Serializable {
	
	private int no;
	private Test test;

	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public Test getTest() {
		return test;
	}
	public void setTest(Test test) {
		this.test = test;
	}
	
}
Aşağıdaki gibi bir uygulama yapalım :
import org.apache.commons.lang3.SerializationUtils;

public class DeepCloneTestApacheLang {
	
	public static void main(String[] args) {
		
		Test t=new Test();
		t.setNo(1);
		t.setName("Tester");
		
		TestDeep parent=new TestDeep();
		parent.setNo(100);
		parent.setTest(t);
					
		TestDeep t2=(TestDeep)SerializationUtils.clone(parent);
		
		t2.setNo(1283);
		t2.getTest().setNo(1453);
		t2.getTest().setName("Deep");
		
		System.out.println("Orjinal:"+t.getNo()+","+t.getName());
		System.out.println("Orjinal Deep:"+t2.getNo());
		System.out.println("Kopya Deep:"+t2.getTest().getNo()+","
				+t2.getTest().getName());	
		
	}

}
Bu uygulamayı çalıştırdığımızda aşağıdaki gibi bir çıktı üretecektir :
Orjinal:1,Tester
Orjinal Deep:1283
Kopya Deep:1453,Deep
Görüldüğü gibi t nesnesi değiştirilmesine rağmen orjinal nesne değişmemiştir.
t2.getTest().setNo(1453);
t2.getTest().setName("Deep");
Sonuç olarak bir nesneyi içindeki nesnelerin hepsini en alttaki nesnelere gidecek şekilde içerecek şekilde kopyalamak için SerializationUtils clone() yöntemi kullanılabilir. Ancak nesnelerin tümü Serializable olmalıdır.

Örnek

Java'da JSON Kullanarak Deep Clone Yapan Örnek

Java'da bir object clone() yöntemi ile clone'u (kopya) alınabilir. Ancak bu kopya işlemi sadece nesnenin kopyasını alır. Nesnenin sahip olduğu class tipindeki nesnelerin koypasını almaz. Bunun için nesne JSON'a çevrilip sonradan yeniden object'e çevrilebilir.
Aşağıdaki gibi bir test sınıfı olsun :
public class Test
{
	
	private int no;
	private String name;
	
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
}
Bu test sınıfını kullanan bir ana sınıfı aşağıdaki gibi yapabiliriz :
public class TestDeep{
	
	private int no;
	private Test test;
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public Test getTest() {
		return test;
	}
	public void setTest(Test test) {
		this.test = test;
	}
	
}

Gson

Bu yöntemde Serializable ve Cloneable interfaces'lerinin implement edilmesine gerek yoktur.
Aşağıdaki gibi bir uygulama yapalım :
import com.google.gson.Gson;
public class DeepCloneTestGson {
	
	public static void main(String[] args) {
		
		Test t=new Test();
		t.setNo(1);
		t.setName("Tester");
		
		TestDeep parent=new TestDeep();
		parent.setNo(100);
		parent.setTest(t);
							
		Gson gson = new Gson();
		TestDeep t2 = gson.fromJson(gson.toJson(parent), TestDeep.class);
		
		t2.setNo(1283);
		t2.getTest().setNo(1453);
		t2.getTest().setName("Deep");
		
		System.out.println("Orjinal:"+t.getNo()+","+t.getName());
		System.out.println("Orjinal Deep:"+t2.getNo());
		System.out.println("Kopya Deep:"+t2.getTest().getNo()+","
				+t2.getTest().getName());	
		
	}
}
Bu uygulamayı çalıştırdığımızda aşağıdaki gibi bir çıktı üretecektir :
Orjinal:1,Tester
Orjinal Deep:1283
Kopya Deep:1453,Deep
Görüldüğü gibi t nesnesi değiştirilmesine rağmen orjinal nesne değişmemiştir.
t2.getTest().setNo(1453);
t2.getTest().setName("Deep");
Sonuç olarak bir nesneyi içindeki nesnelerin hepsini en alttaki nesnelere gidecek şekilde içerecek şekilde kopyalamak için Gson kullanılabilir.

Jackson

Java'da yaygın kullanılan bir JSON kütüphanesi de Jackson'dır. Aynı uygulamayı Jackson ile yapınca da aynı sonuç alınacaktır.
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class DeepCloneTestJackson {
	
	public static void main(String[] args) {
		
		Test t=new Test();
		t.setNo(1);
		t.setName("Tester");
		
		TestDeep parent=new TestDeep();
		parent.setNo(100);
		parent.setTest(t);
							
		TestDeep t2=null;
		try {
			ObjectMapper objectMapper = new ObjectMapper();
			t2 = objectMapper
				      .readValue(objectMapper.writeValueAsString(parent), TestDeep.class);
			
			t2.setNo(1283);
			t2.getTest().setNo(1453);
			t2.getTest().setName("Deep");
			
			System.out.println("Orjinal:"+t.getNo()+","+t.getName());
			System.out.println("Orjinal Deep:"+t2.getNo());
			System.out.println("Kopya Deep:"+t2.getTest().getNo()+","
					+t2.getTest().getName());	
			
		} catch (JsonMappingException e) {
			e.printStackTrace();
		} catch (JsonProcessingException e) {
			e.printStackTrace();
		}
		
	}
}
Jakson'ı Maven ile eklemek için aşağıdaki gibi bağımlılık eklenmesi gerekir:
<dependency>
	<groupId>com.fasterxml.jackson.core</groupId>
	<artifactId>jackson-core</artifactId>
	<version>2.13.2</version>
</dependency>
<dependency>
	<groupId>com.fasterxml.jackson.core</groupId>
	<artifactId>jackson-databind</artifactId>
	<version>2.13.2.2</version>
</dependency>




Bu Sayfayı Paylaş:

İletişim Bilgileri

Takip Et

Her Hakkı Saklıdır. Bu sitede yayınlanan tüm bilgi ve fikirlerin kullanımından fibiler.com sorumlu değildir. Bu sitede üretilmiş , derlenmiş içerikleri, fibiler.com'u kaynak göstermek koşuluyla kendi sitenizde kullanılabilirsiniz. Ancak telif hakkı olan içeriklerin hakları sahiplerine aittir