Object对象的通用方法-clone

什么是clone?

GoF设计模式里有一个模式为原型模式,用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.
简单的说就是clone一个对象实例。使得clone出来的copy和原有的对象一模一样。

clone方法的通用约定非常弱,一般的含义是,对任何对象x,表达式:
x.clone() != x
x.clone().getClass() == x.getClass()
x.clone().equals(x)
但是这些都不是绝对的要求。我们的克隆是:创建它的类的新实例,同时拷贝内部的数据结构。

Object的clone:

堆上的内存存储解释的话(不计内务内存),对一个对象a的clone就是在堆上分配一个和a在堆上所占存储空间一样大的一块地方,然后把a的堆上内存的内容复制到这个新分配的内存空间上。

Object的clone是将对象简单的实行域对域的copy,实例中仅仅拷贝了一个对User的引用,还是指向的同一User对象。即:Shallow clone -默认的浅克隆

//*************************** Shallow clone
class User{
	String name;
}
class Book implements Cloneable{
	User user;
	String name;
	int price;
	@Override
	protected Book clone() throws CloneNotSupportedException {
		//Object.clone返回Object,在覆盖clone方法时转换,客户端就不必再转换了
		//通则:不要让客户去做任何类库能够替客户完成的事情
		return (Book)super.clone();
	}
}
//*************************** Deep clone
class User2 implements Cloneable{
	String name;
	int age;
	@Override
	public User2 clone() throws CloneNotSupportedException {
		return (User2) super.clone();
	}
}
class Book2 implements Cloneable{
	User2 user;
	String name;
	int price;
	@Override
	public Book2 clone() throws CloneNotSupportedException {
		Book2 book2=null;
		book2=(Book2)super.clone();
		if(user!=null){//可变引用类型深克隆
			book2.user=user.clone();
		}
		return book2;
	}
}
//*************************** 
/**
 *@Function: 克隆
 *@Author: April
 *@Date: 2014-3-25
 */
public class CloneTest {
	public static void main(String[] args) throws CloneNotSupportedException {
		shallow();
		System.out.println();
		deep();
	}
	static void shallow() throws CloneNotSupportedException{
		User user=new User();
		user.name="April_1";
		Book book=new Book();
		book.user=user;
		book.price=1111;
		book.name="Java_1";
		//clone
		Book cloneBook= book.clone();
		//可变引用类型,仅仅只copy了一个指向同一个对象的引用
		cloneBook.user.name="April_2";
		//不可变引用类型,浅克隆不会改变其内部状态
		cloneBook.name="Java_2";
		//基本类型
		cloneBook.price=2222;
		//output: April_2 , Java_1 ,price=1111
		System.out.format("%s , %s ,price=%d",book.user.name,book.name,book.price);
	}
	static void deep() throws CloneNotSupportedException{
		User2 user2=new User2();
		user2.name="April_1";
		user2.age=11;
		Book2 book2=new Book2();
		book2.user=user2;
		book2.price=1111;
		book2.name="Java_1";
		Book2 cloneBook2= book2.clone();
		cloneBook2.user.name="April_2";
		cloneBook2.user.age=22;
		cloneBook2.name="Java_2";
		cloneBook2.price=2222;
		//output: April_1 , Java_1 ,price=1111,user.age=11
		System.out.format("%s , %s ,price=%d,user.age=%d",book2.user.name,book2.name,book2.price,book2.user.age);
	}
}

为什么需要浅copy?

  1. 效率和简单性,简单的copy一个对象在堆上的的内存比遍历一个对象网然后内存深copy明显效率高并且简单。 
  2. 不给别的类强加意义。如果A实现了Cloneable,同时有一个引用指向B,如果直接复制内存进行深copy的话,意味着B在意义上也是支持Clone的,但是这个是在使用B的A中做的,B甚至都不知道。破坏了B原有的接口。
  3. 有可能破坏语义。如果A实现了Cloneable,同时有一个引用指向B,该B实现为单例模式,如果直接复制内存进行深copy的话,破坏了B的单例模式。
  4. 方便且更灵活,如果A引用一个不可变对象,则内存deep copy是一种浪费。Shadow copy给了程序员更好的灵活性。

怎样去实现clone?

  1. 声明实现Cloneable接口。 否则会抛出CloneNotSupportedException
  2. 调用super.clone拿到一个对象,如果父类的clone实现没有问题的话,在该对象的内存存储中,所有父类定义的field都已经clone好了,该类中的primitive和不可变类型引用也克隆好了,可变类型引用都是浅copy。
  3. 把浅copy的引用指向原型对象新的克隆体。(拷贝任何包含内部"深层结构"的可变对象,并用指向新对象的引用代替原来指向这些对象的引用)
  4. 注:shallow clone还是deep clone主要取决于对象的域是什么性质的。如果是基本类型或不可变引用类型(如:String),就应该用shallow clone,其他引用类型用deep clone




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值