Java学习心得之clone方法(原型模式)

一、clone方法简介

含义:顾名思义,克隆就是复制的意思。调用clone方法时,首先会分配一个和源对象同样大小的空间,然后再这个空间中创建新对象

Java中创建新对象的方式有两种:new 和 clone

那么,它们有什么区别:

  • new : 执行到new操作符时,会根据后面类型分配相应大小的空间,然后通过构造函数填充各个域,我们称之为初始化。
  • clone:调用clone方法时,与new一样首先分配一个和源对象相同的空间,然后使用源对象中的各个域来填充新对象的域。
同样的,在new和clone在内存中创建新对象后,都会将对象的引用发布到外部。

代码实测:
1.复制引用
public static void main(String[] args) {
	Dog d = new Dog("black",5,30);
	Dog d1 = d;
	System.out.println(d);
	System.out.println(d1);
}

输出结果:
Dog@2a139a55
Dog@2a139a55

我们看到,两个对象输出的是同一个地址,因此,我们可以说d和d1指向的是同一个对象,这种现象我们称之为引用的复制。
其内存情况如下:
2.复制对象
public static void main(String[] args) throws CloneNotSupportedException {
	Dog d = new Dog("black",5,30);
	Dog d1 = (Dog)d.clone();
	System.out.println(d);
	System.out.println(d1);
}

输出结果:
Dog@2a139a55
Dog@15db9742

我们看到,两个对象的地址不一样,因为通过clone后,创建了一个新的对象,而不是把源对象的地址赋给了新的引用变量。
其内存情况如下:


二、深拷贝和浅拷贝


区别:
 

上图中,我们看到:
浅拷贝:新对象的color属性指向源对象color属性的地址,其他属性复制了一份新的。
深拷贝:新对象的color属性指向一个新的字符串对象,其他属性复制了一份新的。


那么,clone是深拷贝or浅拷贝
Dog实例:
public class Dog implements Cloneable{
	private int weight;
	private Head head;
	public Dog(Head head, int weight) {
		this.weight = weight;
		this.head = new Head();
	}
	
	static class Head{
		private Face face;
	}
	static class Face{
		
	}

}

测试代码:
public static void main(String[] args) throws CloneNotSupportedException {
	Dog d = new Dog(new Head(),5);
	Dog d1 = (Dog)d.clone();
	System.out.println(d.getHead());
	System.out.println(d1.getHead());
	
}

输出结果:
Dog$Head@2a139a55
Dog$Head@2a139a55

从输出结果看,clone属于浅拷贝。

那么,如何实现深拷贝呢?我们可以通过重写clone方法,将Dog中的Head对象也进行clone,注意要进行clone该类要实现Cloneable接口。
public class Dog implements Cloneable{
	private int weight;
	private Head head;
	public Dog(Head head, int weight) {
		this.weight = weight;
		this.head = head;
	}
	
	public Object clone() throws CloneNotSupportedException{
		Dog newDog = (Dog)super.clone();
		newDog.head = (Head)head.clone();
		return newDog;
	}
	
	static class Head implements Cloneable{
		private Face face;
		
		public Head(){
			face = new Face();
		}
		public Face getFace() {
			return face;
		}


		public void setFace(Face face) {
			this.face = face;
		}


		public Object clone() throws CloneNotSupportedException{
			return super.clone();
		}
	}
	static class Face{


	}
}

测试代码:
public static void main(String[] args) throws CloneNotSupportedException {
	Dog d = new Dog(new Head(),5);
	Dog d1 = (Dog)d.clone();
	System.out.println(d.getHead());
	System.out.println(d1.getHead());
}

输出结果:
Dog$Head@2a139a55
Dog$Head@15db9742

从结果中,看出对象进行了深拷贝。那么,这里进行的深拷贝是彻底的吗?

测试代码(同上例子,这次我我们打印Head对象中的Face对象)
public static void main(String[] args) throws CloneNotSupportedException {
	Dog d = new Dog(new Head(),5);
	Dog d1 = (Dog)d.clone();
	System.out.println(d.getHead().getFace());
	System.out.println(d1.getHead().getFace());
}

输出结果:
Dog$Face@2a139a55
Dog$Face@2a139a55

结论是,这次的拷贝并不彻底

由深拷贝的原理得知,我们要继续彻底的对Dog进行拷贝,就要在Head对象中继续重写clone方法,将Face进行clone,
这里理解了的朋友就会问:要是Face对象中还有一个Eye对象呢?
没错,这个时候要彻底的拷贝,就要继续在Face中重写Clone方法,将Eye进行拷贝,这样的话是不是没有真正意义上的彻底的深拷贝呢?
理论上是这样的,但是在我们实际开发中,基本上不会碰到真样的情况的。我们只要理解浅拷贝和深拷贝的原理即可。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值