clone()方法有什么作用

1、先了解值传递和引用传递

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()方法完成深复制(非数据类型本身也要实现Cloneable接口重写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

2、深复制和浅复制的区别:

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

在这里插入图片描述

对于自定义的类的对象实例做引用其他对象的变量:

/**
 * @ClassName TestDemo20
 * @Description clone
 * @Author lzq
 * @Date 2018/10/31 20:52
 * @Version 1.0
 **/

class Money implements Cloneable{
    double money = 10.0;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

class Person implements Cloneable{
    private String name;
    Money m;
    public Person(String name) {
        this.name = name;
        this.m = new Money();
    }
    //重写Object的克隆方法
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person person = (Person)super.clone();  //克隆Person对象
        person.m = (Money)this.m.clone();   //克隆在Person对象中引用指向的对象
        return person;
    }
}

public class TestDemo20 {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1 = new Person("caocao");
        Person person2 = (Person)person1.clone();

        System.out.println(person1.m.money);
        System.out.println(person2.m.money);

        person2.m.money = 1000.0;

        System.out.println(person1.m.money);
        System.out.println(person2.m.money);

    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值