浅谈自己理解的深拷贝和浅拷贝

在自己之前的文章中写过原型模式的笔记,原型模式中稍微理解了一下深克隆和浅克隆。今天在复习中用具体的方法进行一下深克隆。

一、为什么用到克隆

我们对一个对象进行一番操作后,这个对象就有着很多属性。这个时候我们如果去新建一个对象,又得进行刚才操作的一溜串的操作,就略显麻烦。这个时候克隆就出现了。

二、深克隆和浅克隆的区别

讲讲区别前,来讲讲要克隆的对象的一些属性。
比如 一个person对象,中包涵了另一个对象phone

java中只有两种变量类型,一个基本数据类型,一个是引用数据类型。除了那8个基本数据类型,其他变量都是引用类型。

浅克隆和深克隆的区别,就区别于引用类型拷贝上

浅克隆,会返回一个新对象,新对象的属性和原对象属性完全一致,但是对于引用类型属性的复制,复制的是引用地址。也就是说新对象和原对象的引用的是同一块内存的对象。当对新对象的引用类型属性进行修改,原对象对应属性也会随之被修改。

从上面的person对象进行解释,也就是当person2对象浅拷贝person1对象时,这个两个对象是公用一个phone对象的。

深克隆,返回一个新对象,新对象属性和原对象属性完全一致,并且引用类型的对象也会被克隆,新对象的引用类型属性的引用指向新克隆的对象。
也就是说,当person2对person1进行深克隆的时候,person2对象有自己的phone,person1也有自己phone,两个person不在共用一部phone

三、如何实现浅克隆或者深克隆

实现克隆有两种方法
第一种:要被克隆的对象实现Cloneable接口,并重写Clone()方法。
第二种:通过实现serializable接口,通过对象的序列化和反序列化来实现克隆(对象流方式)

第一种克隆又分为两种情况
(1)重写Clone()方法的时候,只是调用父类的方法。这个是浅克隆

	@Override
	protected Person clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		return (Person) super.clone();
	}

(2)重写Clone方法时,进行进一步的克隆。代码如下

	@Override
	protected Person clone() throws CloneNotSupportedException {
		Person person = (Person) super.clone();
		if(person.phone!=null) {
			 person.phone=phone.clone();
		}
		return person;
	}
}

很容易看到这个方法进行深克隆的局限性,拿上面例子来说,再次拷贝phone的时候,phone就又得必须满足,实现cloneable接口和重写Clone()方法,如果phone又有其他的引用类型?咋办?再去实现接口重写方法?显然如多嵌套多和引用类型属性这个方法并不太适用。

第二种方式克隆

public class CloneUtil {
	
		@SuppressWarnings("unchecked")
		public static <T extends Serializable> T clone(T obj) throws
		Exception {
		ByteArrayOutputStream bout = new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(bout);
		oos.writeObject(obj);
		ByteArrayInputStream bin = new
		ByteArrayInputStream(bout.toByteArray());
		ObjectInputStream ois = new ObjectInputStream(bin);
		return (T) ois.readObject();
		}
	}

接下来对比一下,常见的类型的深浅克隆的比较

public class Test1 {
	
	public static void main(String[] args) {
		
	
		
		try {
		//深克隆
		Person p1 = new Person("张三",300,175, new Phone("小米","黑色"));
		Person p2 = CloneUtil.clone(p1); 
		System.out.print("深克隆String比较:");
		System.out.println(p1.getName()==p2.getName());
		p2.getPhone().setBrand("华为");
		System.out.print("深克隆Integer比较:");
		System.out.println(p1.getTall()==p2.getTall());
		System.out.println("p1"+p1);
		//浅克隆
		Person p3 = new Person("李四", 18,new Integer(500), new Phone("红米","黑色"));
		Person p4 = p3.clone();
		System.out.print("浅克隆String比较:");
		System.out.println(p3.getName()==p4.getName());
		p4.getPhone().setBrand("华为");
		System.out.print("浅克隆Integer比较:");
		System.out.println(p4.getTall()==p3.getTall());
		System.out.println("p3"+p3);
		} catch (Exception e) {
		e.printStackTrace();
		}
	}
}

在这里插入图片描述

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页