Java基础--详解Object类中的clone方法

clone()方法

clone()方法将对象复制了一份并返回给调用者。一般而言,clone()方法满足:

  1. 对任何对象a,都有a.clone() != a,即克隆对象与源对象不同
  2. 对任何对象a,都有a.clone().getClass == a.getClass,即克隆对象与源对象的类型相同

clone()方法时Object类的一个方法,因此,所有的类都具有这个方法。clone()的作用在于复制对象,在复制对象的过程中,首先要分配一个和源对象同样大小的空间,在这个空间中创建一个新的对象。

众所周知,我们可以使用new来创建一个对象,那么使用new操作符和使用clone方法复制一个对象有什么区别呢?

new操作符的本质是分配内存,程序执行到new操作符时,首先去看new操作符时,首先去看new操作符后边的类型,因为不同的类型分配的内存空间不同,知道了类型就能决定要分配的内存空间多大。然后调用构造函数,填充对象各个域,这一步才叫对象的初始化。构造方法返回后,一个对象创建完毕,可以把他的引用(地址)发布到外部,在外部就可以使用这个引用来操纵这个对象。而clone在第一步是和new相似的,都是分配内存,调用clone方法时,分配的内存和源对象相同,然后使用源对象中对应的各个域,填充新对象的域。填充完成后,clone方法返回,一个新的相同的对象被创建,同样可以把这个新对象的引用发布到外部。

复制引用与复制对象

要注意复制引用和复制对象的区别。这两者最大的差异在于有没有在堆区建立一个新的对象。

复制引用

ClassA clazz1 = new ClassA(123);
ClassA clazz2 = clazz1;

上边的代码就是一个复制引用,clazz1和clazz2都指向了同一个对象ClassA(123)。我们可以通过这张图来理解它:

复制对象

ClassA clazz1 = new ClassA(123);
ClassA clazz2 = (ClassA) clazz1.clone();

复制对象也就是通过我们本文的重点clone()方法来实现,出clazz1和clazz2都分别指向一个对象,虽然这两个对象的内容相同,但地址不同,因此是两个不同的对象。上图你就明白了:

很明显,通过复制对象我们产生了一个新的对象,当我们对克隆的对象进行修改时,并不会影响到源对象,同理,修改源对象也不会影响到克隆对象。

浅复制和深复制

浅复制

浅复制指的是被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的 引用仍然指向原来的对象。换句话说,浅复制并不关心它所引用的的对象。

例如:类A引用了类B,当我们对类A进行克隆产生一个类C,类C会使用类A原本对类B的引用,即类C直接对类B进行引用。看图说话:

深复制

被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量都指向被复制过的新对象,而不是原有的哪些被引用的对象。也就是说,深复制在浅复制的基础上,将源对象中引用的对象也都复制一遍,用于给克隆对象进行引用。

浅复制和深复制的实现

java.lang.Object类中的clone()方法是浅复制,我们要使用浅复制则直接调用类原有的clone方法即可,那么我们要如何实现深复制呢?

实现深复制的关键就在于覆盖Object中的clone方法。为了要在clone对象时进行深复制,那么就要Cloneable接口,覆盖并实现clone方法,除了调用父类中的clone方法得到新的对象,还要将该类中的引用变量也clone出来。

public class Test {
	    static class Body implements Cloneable {
	        public Head head;

	        public Body() {
	        }

	        public Body(Head head) {
	            this.head = head;
	        }

	        @Override
	        protected Object clone() throws CloneNotSupportedException {
	            Body newBody = (Body) super.clone();
	            newBody.head = (Head) head.clone();
	            return newBody;
	        }
	    }

	    static class Head implements Cloneable {
	        public Face face;

	        public Head() {
	        }

	        public Head(Face face) {
	            this.face = face;
	        }

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

	    static class Face implements Cloneable {
	        public Face() {
	        }
	    }

	    public static void main(String[] args) throws CloneNotSupportedException {
	        Body body = new Body(new Head());
	        Body body1 = (Body) body.clone();
	        System.out.println("body == body1 : " + (body == body1));
	        System.out.println("body.head == body1.head : " + (body.head == body1.head));
	    }
	}

运行main函数的结果为:

由此可见,我们实现了深复制。但是完全的实现深复制是很难的,如上边的代码中,可能Face类中还存在着别的引用,上边的深复制也是一个不完全的深复制。

本文参考自https://www.cnblogs.com/xzwblog/p/7230788.html

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值