Java中clone()方法的使用

Java编程思想

对象克隆是指创建已有对象的一个拷贝,如果想要修改一个对象,但同时不想改变调用者的对象,那么克隆会是很好的解决方式。
在Java中,实现对象的克隆只需要覆盖Object提供的clone()方法,并将方法访问级别改为public,同时要注意对象所属类必须实现Cloneable接口,否则在调用clone()方法时会抛出CloneNotSupportedException异常。

1 clone()方法的使用

class Test implements Cloneable{
	public int ii;
	public String ss;
	public Test2 test2;
	
	public Test() {
		super();
	}

	public String format() {
		return String.format("ii = %s, ss = %s, test2 = %s", ii, ss, test2);
	}
	
	@Override
	public Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
	
}

class Test2 implements Cloneable{

	public int ii2;
	
	@Override
	public Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
	
}

public class CloneTest {
	public static void main(String[] args) throws Exception {
		Test t = new Test();
		t.ii = 1;
		t.ss = "1";
		t.test2 = new Test2();
		
		Test t2 = (Test) t.clone();
		
		System.out.println(t);
		System.out.println(t2);
		System.out.println(t.format());
		System.out.println(t2.format());
		
		t2.ii = 2;
		t2.ss = "2";
		System.out.println(t.format());
		System.out.println(t2.format());
	}
}

输出:

gdou.laiminghai.Test@2a139a55
gdou.laiminghai.Test@15db9742
ii = 1, ss = 1, test2 = gdou.laiminghai.Test2@7d4991ad
ii = 1, ss = 1, test2 = gdou.laiminghai.Test2@7d4991ad
ii = 1, ss = 1, test2 = gdou.laiminghai.Test2@7d4991ad
ii = 2, ss = 2, test2 = gdou.laiminghai.Test2@7d4991ad

可以看到,通过覆盖clone()方法,在clone()方法中通过super.clone()的调用,我们可以获得对象的拷贝,两个对象引用指向不同的内存区域,同时拥有了相同的属性值。当我们对拷贝对象作出修改时,并不会影响原有的对象。

2 浅拷贝和深拷贝

从上面的例子我们可以看到,clone()方法的使用的确返回对象的一个拷贝,但如果对象中的属性是另一个引用类型的话,那么clone()方法的简单调用并不会把该引用指向的对象再作一次拷贝,同时把新对象属性里的引用指向这个拷贝,而只是把引用(内存地址)作一次拷贝,结果是两个属性引用指向的仍然是同一个对象。这种只拷贝了原始数据类型的拷贝,我们就称作浅拷贝。(这里我们可能发现了,String类型是引用类型,为什么拷贝对象中String类型变量改变了,原有对象却没改变,其实主要是因为String的不可变性,拷贝对象改变的只是引用而引用指向的内容)
浅拷贝就有深拷贝,深拷贝会拷贝所有的原始数据属性,同时也拷贝引用属性指向的动态分配的内存。那么要如何实现深拷贝呢?

@Override
	public Object clone() throws CloneNotSupportedException {
		Test t = (Test)super.clone();
		t.test2 = (Test2) test2.clone();
		return t;
	}

方法就是在覆盖clone()方法时,对对象中引用变量也明确调用一次clone()方法进行一次克隆。
修改后输出:

gdou.laiminghai.Test@2a139a55
gdou.laiminghai.Test@15db9742
ii = 1, ss = 1, test2 = gdou.laiminghai.Test2@7d4991ad
ii = 1, ss = 1, test2 = gdou.laiminghai.Test2@28d93b30
ii = 1, ss = 1, test2 = gdou.laiminghai.Test2@7d4991ad
ii = 2, ss = 2, test2 = gdou.laiminghai.Test2@28d93b30

3 Object的clone()方法做了什么

我们发现,在覆盖clone()方法的时候,我们有一句super.clone()是必有的,通过super.clone()方法传递调用,我们知道,最后一定会调用到Object的clone()方法,那么,Object.clone()方法会做什么呢?
Object.clone()会检查原先的对象有多大(通过运行时类型信息RTTI判断),再为新对象腾出足够多的内存,并通过“按位复制”将所有二进制位从原来的对象复制到新对象的存储空间。

猜你喜欢

转载自blog.csdn.net/CrazyLai1996/article/details/85034436
今日推荐