java对象的深克隆与浅克隆

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a695929533/article/details/51077651

我们在复制java对象的时候,往往使用Object.clone();这个方法。但是,如果对象内引用了另一个对象——假如说,a1对象内引用另一个对象b1,如果a2克隆a1,那么a2引用的b对象,还是b1吗?


根据某些时候的业务需求,分成了两种情况:

浅克隆:复制对象,但引用不变(依旧是B1)。

深克隆:复制对象,连同对象的引用的对象,一起复制(生成B2)。


可以做个测试:修改a2的引用中b的成员变量,然后同时输出a1的引用b的成员变量的值,进行比较。


浅克隆----------------------------------

类A:

public class A implements Cloneable {
	 private String name;
	 private int age;
	 private B b;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public B getB() {
		return b;
	}
	public void setB(B b) {
		this.b = b;
	}
	@Override  
    public Object clone() throws CloneNotSupportedException  
    {  
        return super.clone();  
    }  
}


类B:

public class B {
		private String name;
		private int age;
		public String getName() {
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}
		public int getAge() {
			return age;
		}
		public void setAge(int age) {
			this.age = age;
		}
}

测试类:

public static void main(String[] args) throws CloneNotSupportedException {
		A a1 = new A();
		B b1 = new B();
		a1.setName("A1");
		a1.setAge(1);
		a1.setB(b1);
		b1.setName("B1");
		b1.setAge(11);
	
		A a2 =  (A) a1.clone();
		a2.getB().setName("B2");
		a2.getB().setAge(22);
		
		System.out.println("a1的B对象属性name:"+a1.getB().getName());
		System.out.println("a1的B对象属性age:"+a1.getB().getAge());
		
		System.out.println("a2的B对象属性name:"+a2.getB().getName());
		System.out.println("a2的B对象属性age:"+a2.getB().getAge());
	}


输出结果:

a1的B对象属性name:B2
a1的B对象属性age:22
a2的B对象属性name:B2
a2的B对象属性age:22


深克隆----------------------------------

类A:

public class A implements Cloneable {
	 private String name;
	 private int age;
	 private B b;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public B getB() {
		return b;
	}
	public void setB(B b) {
		this.b = b;
	}
	@Override  
    public Object clone() throws CloneNotSupportedException  
    {  
		A a = (A)  super.clone(); 
		a.setB((B)a.getB().clone());
		return a;
    }  
}

类B:

public class B implements Cloneable{
		private String name;
		private int age;
		public String getName() {
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}
		public int getAge() {
			return age;
		}
		public void setAge(int age) {
			this.age = age;
		}
		@Override  
	    public Object clone() throws CloneNotSupportedException  
	    {  
	        return super.clone();  
	    }  
}

测试类:

public static void main(String[] args) throws CloneNotSupportedException {
		A a1 = new A ();
		B b1 = new B ();
		
		a1.setAge(1);
		a1.setB(b1);
		b1.setName("B1");
		b1.setAge(11);
	
		A a2 =  (A) a1.clone();
		a2.getB().setName("B2");
		a2.getB().setAge(22);
		
		System.out.println("a1的B对象属性name:"+a1.getB().getName());
		System.out.println("a1的B对象属性age:"+a1.getB().getAge());
		
		System.out.println("a2的B对象属性name:"+a2.getB().getName());
		System.out.println("a2的B对象属性age:"+a2.getB().getAge());
	}

输出结果:

a1的B对象属性name:B1
a1的B对象属性age:11
a2的B对象属性name:B2
a2的B对象属性age:22


分析:通过比较结果,我们可以看到:通过浅克隆进行克隆对象的操作,只是克隆了对象的成员变量和引用,对引用的对象并未进行深层次的复制;而通过深克隆进行克隆对象的操作,不仅仅克隆了对象的成员变量,连被克隆对象的引用对象都一起克隆了。

那么,如何实现两者呢?

需要事先说明的是,如果想要进行最基本的克隆对象操作,这个对象的类必须已经实现了Cloneable接口,并且重写了clone()这个方法(方法返回 super.clone()即可)。

浅克隆,只是需要我们对直接克隆的对象,实现这个接口即可。

深克隆就复杂一点,不过也好理解。

拿上面的例子说,首先,我们让B实现Cloneable这个接口,重写clone()这个方法。然后,让A也实现Cloneable接口,只是A的clone()方法,要变通一下:我们自己克隆a1,获得a,然后通过a获取b,再克隆b,再赋给a,最后返回a。简而言之,就是从a里面拿出来b,克隆出一个新的b,再放回去,原来的b被掉包了。

思考,如果B里面有个引用C,那么A,B,C那该怎样写呢?留给读者思考。

猜你喜欢

转载自blog.csdn.net/a695929533/article/details/51077651