Java中的clone()方法有什么作用

Java在处理基本数据类型(例如int、char、double等)时,都是采用值传递(传递的是输入参数的副本)的方式执行,除此之外的其它类型(对象啊,String类型等)都是按引用传递(传递的是对象的一个引用)的方式执行。对象除了在函数调用时是引用传递,在使用“=”也是采用引用传递

class Obj {
	private int i = 0;
	public int getI() {
		return i;
	}
	public void setI(int i) {
		this.i = i;
	}
	public void changeI() {
		this.i = 1;
	}
}
public class LianXi {

	public static void main(String[] args) {
		Obj a = new Obj();
		Obj b = a;
		b.changeI();
		System.out.println("a:"+a.getI());
		System.out.println("b:"+b.getI());
	}
}

运行结果:

a:1
b:1

在实际编程中,经常需要从某个已知对象A创建出另一个与A具有相同状态的对象B,并且对B的修改不会影响到A的状态,但从上面的实例中,我们会发现仅仅通过简单的赋值操作显然是无法达到这个目的的(b对象对i的修改影响到了a对象中的i),所以Java提供了一个简单有效的clone()方法来满足这个需求。

Java中所有的类都默认继承自Object类,而Object类中提供了一个clone()方法,这个方法的作用是返回一个Object对象的复制,这个复制方法返回的是一个新的对象而不是一个引用。以下是使用clone()方法的步骤:

  1. 实现clone的类首先需要继承Cloneable接口(Cloneable接口实质是一个标识接口,没有任何的接口方法)
  2. 在类中重写Object类中的clone()方法
  3. 在clone()方法中调用super.clone()。无论clone类继承结构是什么,super.clone()会直接或间接java.lang.Object类中的clone()方法。
  4. 把浅复制的引用指向原型对象新的克隆体。

上面的例子引入clone()方法后代码:

class Obj implements Cloneable {
	private int i = 0;
	public int getI() {
		return i;
	}
	public void setI(int i) {
		this.i = i;
	}
	public void changeI() {
		this.i = 1;
	}
	public Object clone() { //重写clone()方法
		Object o = null;
		try {
			o = (Obj)super.clone();
		}catch(CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return o;
	}
}
public class LianXi {

	public static void main(String[] args) {
		Obj a = new Obj();
		Obj b = (Obj)a.clone();
		b.changeI();
		System.out.println("a:"+a.getI());
		System.out.println("b:"+b.getI());
	}
}

在开发人员自定义复制构造函数时,会存在浅复制和深复制之分,Java在重载clone()方法时也存在同样的问题,当类中只有一些基本数据类型时,采用上述的方法就可以了,但是当类中包含了一些对象时,就需要用到深复制了(没错,上面那个就是浅复制),实现方法是在对对象调用clone()方法完成复制后,接着对对象中的非基本数据类型的属性也调用clone()方法完成深复制,实例如下:

class Obj implements Cloneable {
	private Date birth = new Date();  //对象
	public Date getBirth() {
		return birth;
	}
	public void setBirth(Date birth) {
		this.birth = birth;
	}
	public void changeDate() {
		this.birth.setMonth(4);
	}
	public Object clone() {
		Obj o = null;
		try {
			o = (Obj)super.clone(); //先执行浅复制
		}catch(CloneNotSupportedException e) {
			e.printStackTrace();
		}
		o.birth = (Date)this.getBirth().clone(); //深复制,没有这一步的话,两个对
		 //象的运行结果都是4月,原因是后面的深复制和浅复制的区别
		return o;
	}
}
public class LianXi {

	public static void main(String[] args) {
		Obj a = new Obj();
		Obj b = (Obj)a.clone();
		b.changeDate();
		System.out.println("a:"+a.getBirth());
		System.out.println("b:"+b.getBirth());
	}
}

运行结果:

a:Tue Sep 25 13:14:44 CST 2018
b:Fri May 25 13:14:44 CST 2018

深复制和浅复制的区别:

  • 浅复制:被复制对象的所有变量都含有与原来对象相同的值,而所有对其他对象的引用任然指向原来的对象,换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象
  • 深复制:被复制对象的所有变量都含有与原来对象相同的值,除去那些引用其他对象的变量,那些引用其他对象的变量将指向被复制的新对象,而不知原来那些被引用的对象,换言之,深复制把浅复制的对象所引用的对象都复制了一遍。

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/QQ2899349953/article/details/82838305