java的浅克隆和深克隆

为什么要存在克隆?

首先new出来的对象时初始对象,如果对象里的数据是时刻发生变化的,除非你给初始的对象一一赋值或者使用构造器,
上面的也太繁琐了,而用引用就更不行了,旧对象发生变化那新对象也会跟着发生变化,所以产生了克隆
看源码

 protected native Object clone() throws CloneNotSupportedException;

native修饰的,说明克隆比自己一个个赋值要快
克隆分为两种

  1. 浅克隆:
  2. 深克隆

这两种区别就在深和浅,代表着深层次和浅层次,如果对象中只有那几种数据类型比如:int,String,char等,这两种就没有区别,
但是 如果对象里有另一个对象的引用,那这个对象有分为两层了,浅克隆只可怜那个最上面的一层,而下一层的引用都是一样的,深克隆是所有的层数都克隆

用图形来形象的表示这两种克隆
在这里插入图片描述

浅克隆

需要克隆的类实现Cloneable的接口,其他的都不用修改,

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

测试

public class TestPojo implements Cloneable{
	
	public String a;
	public TestPojo t;
	@Override
	protected Object clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		return super.clone();
	}
	
	public static void main(String[] args) throws Exception{
		 TestPojo t1 = new TestPojo();
		 t1.a = "555";
		 t1.t = new TestPojo();  //新的内部对象
		 TestPojo t2 = (TestPojo) t1.clone();
		 System.out.println(t2 == t1);    //对象的==比较的是引用地址是否相同,equals比较的是值,instanceof比较的是左边是否是右边的子类
		 System.out.println(t2.t == t1.t);
	}
}

在这里插入图片描述

深克隆

(1)将所有的引用类型实现Cloneable重写clone()方法

	@Override
	protected Object clone() throws CloneNotSupportedException {
		TestPojo tp = (TestPojo) super.clone();
		tp.t.clone();
		return tp;
	}

我这因为引用的它自己不用再重写一遍clone() 方法,和浅克隆的区别是修改了 clone() 的内容
测试

public class TestPojo implements Cloneable{
	
	public String a;
	public Test t;
	@Override
	protected Object clone() throws CloneNotSupportedException {
		TestPojo tp = (TestPojo) super.clone();
		tp.t = (Test) t.clone();
		return tp;
	}
}

另一个Test类

public class Test implements Cloneable{
@Override
	protected Object clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		return super.clone();
	}
	public static void main(String[] args) throws Exception{
		 TestPojo t1 = new TestPojo();
		 t1.a = "555";
		 t1.t = new Test();
		 TestPojo t2 = (TestPojo) t1.clone();
		 System.out.println(t2  == t1);
		 System.out.println(t2.t == t1.t);
	}
	}

在这里插入图片描述
警告:
用这种方式实现深克隆一定要慎重,看上面的Test类,我是new了一个TestTestPojo,如果在这样克隆的时候如果没有引用,也就是没有给TestPojo 内部对象一个实例,就深克隆了,那就会报错
java.lang.NullPointerException
这是一个很容易犯的错误
所以有的人就把clone() 方法加了try-catch

@Override
	protected Object clone() throws CloneNotSupportedException {
		TestPojo tp = (TestPojo) super.clone();
		try {
			tp.t = (Test) t.clone();
		} catch (Exception e) {
			e.printStackTrace(); //加就提醒错误,不加就不提醒运行下来
		}
		return super.clone();
	}

上面这种方法就是治标不治本,解决不了根本性问题

(2)用序列化来实现浅克隆向深克隆转化(IO流解决)
public static void main(String[] args) throws Exception{
 TestPojo t1 = new TestPojo();
		 t1.a = "555";
		 t1.t = new Test();
		//将对象写到流里    
		 ByteArrayOutputStream byteOut=new ByteArrayOutputStream();    
		 ObjectOutputStream objOut=new ObjectOutputStream(byteOut);    
		 objOut.writeObject(t1);
		 ByteArrayInputStream byteIn=new ByteArrayInputStream(byteOut.toByteArray());    
		 ObjectInputStream objInput=new ObjectInputStream(byteIn);
		 TestPojo t2 = (TestPojo) objInput.readObject();  
		
		 System.out.println(t2  == t1);
		 System.out.println(t2.t == t1.t);
		 }

TestTestPojo 实现 Serializable 接口就可以了,也可以不用实现Cloneable接口和重写从clone()方法了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值