关闭

java clone

标签: java对象拷贝
240人阅读 评论(0) 收藏 举报
分类:

我们知道Object对象中存在一个clone()方法,他的主要目的就是实现对象的拷贝,从而产生一个新的对象,这两个对象具有相同的值但是存在不同的地址,那么如果我们重写这个方法,应该注意哪些要点呢

1、如果我们需要重写clone()方法,那么我们需要在类中实现Cloneable接口,否则我们重写clone()方法的时候可能会抛出CloneNotSupportedException异常

2、除了声明实现了Cloneable接口以外,我们必须对Object受保护的clone方法提供public的访问权限

因为Object类中提供的clone方法是这样的:

protected native Object clone() throws CloneNotSupportedException;

3、重写的clone方法我们完全没有必要返回Object类型的对象,而是直接返回我们clone的对象类型,因为java1.5已经指出覆盖方法的返回类型可以是被覆盖方法的返回类型的子类了,所有我们只需要返回我们clone的对象类型就可以了,这样不仅优化了代码,还免去了在其他代码上通过强制转换获得对象的开销

4、这个也是非常重要的,我们可能都听说过深拷贝和浅拷贝,但是不知道他们之间到底有什么不同,下面我将做出一定的解释并给出一个实例

前面已经提到clone()方法其实是产生一个具有相同值但是具有不同内存地址的不同对象

那么我们可以更好理解浅拷贝的意思了,浅拷贝就会产生一个具有相同值并且具有相同内存地址的对象,这对于程序来说是应该极力回避的,因为我对这个对象做出的改变其实直接影响到了另一个对象,那么我们直接用赋值语句不更好的解决问题吗,就没有使用clone()方法的必要了

下面给出一个使用clone方法造成浅拷贝的一个实例,可以更好的理解为什么造成了浅拷贝:

class Person implements Cloneable{
	private String name;
	
	public Person(String name, int age) {
		this.name = name;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}

	@Override
	public Person clone() throws CloneNotSupportedException{
		Person result=(Person)super.clone();
		return result;
	}
}

public class Copy implements Cloneable{
	private String name;
	private Person person;
	
	public Copy(String name,Person person) {
		super();
		this.name = name;
		this.person = person;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Person getPerson() {
		return person;
	}
	public void setPerson(Person person) {
		this.person = person;
	}
	
	@Override
	public Copy clone(){
		try {
			Copy copy=(Copy)super.clone();
			return copy;
		} catch (CloneNotSupportedException e) {
			throw(new AssertionError());
		}
	}
}

这段代码初略一看觉得很对,clone()方法是产生了两个不同的Copy对象,但是如果我们写一个main方法测试就会发现问题:

在main()方法里我们加上这两句话:

Copy a=new Copy("hehe",new Person("haha",22));
Copy b=a.clone();
System.out.println(a==b);
System.out.println(a.getName()==b.getName());
System.out.println(a.getPerson()==b.getPerson());

我们发现这里会输出false,true,true

也就是说我们拷贝了两个不同对象a,b,但是他们却占用相同的资源person和name,这其实是不对的,也就是我们所说的浅拷贝,就是没有正确的拷贝出两个完全不同的对象,那么我们应该怎么优化使得产生两个完全不同的对象呢,其实很简单,我们只需要修改Copy类的clone方法和Person类的clone方法就可以了:

person类clone方法:

@Override
public Person clone() throws CloneNotSupportedException{
	Person result=(Person)super.clone();
	result.name=new String(name);
	return result;
}
Copy的clone方法:

@Override
	public Copy clone(){
		try {
			Copy copy=(Copy)super.clone();
			copy.person=person.clone();
			copy.name=new String(name);
			return copy;
		} catch (CloneNotSupportedException e) {
			throw(new AssertionError());
		}
	}
这里由于String类型也不是基本类型,所有也需要进行clone,但是String是final类,不存在clone方法,所有我们直接new一个就可以了,就会产生两个不同对象了

这样我们把person也同样clone一份,那么就会产生两个不同的对象a,b,并且具有相同的值,两个对象之间不会产生任何的干扰

其实对于一个对象的深拷贝,我们首先需要调用super.clone()产生一个新的对象,然会需要对里面的属性进行修正,如果只包含基本类型的属性或者final对象的引用就基本没有修正的必要了,但是不排除序列号等需要修正的可能性。





0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:13853次
    • 积分:231
    • 等级:
    • 排名:千里之外
    • 原创:10篇
    • 转载:2篇
    • 译文:0篇
    • 评论:6条
    文章分类
    最新评论