return*this为什么返回的是克隆_Java克隆对象需要知道的事

Java 语言设计

Java语言设计为:一个类的对象如果想要被克隆,这个类必须实现Cloneable接口。我们先看Cloneable接口:

f93e08d82b4e392f4c352ac136db16b2.png

Java 8 Cloneable接口

  • 一个类实现Cloneable接口,才可以合法调用Object类的clone方法。注意:Cloneable接口是空的,并不包含clone方法。clone方法是在Object类中被声明为protected。如果一个类没有实现Cloneable接口而调用clone方法,会抛出CloneNotSupportedException异常。
  • 按照惯例实现Cloneable接口的类都要重写Object的clone方法。

既然clone方法再Object中,我们进入Object类看看clone方法的声明:

da4f352e79a414e6b0e44a85f862968d.png

Object类的clone方法

clone方法上面的声明太长了就不一块截下来了,可以自己进去看看。

clone方法用于创建此对象的拷贝。拷贝的确切含义可能取决于对象具体的类。一般意图是对于任何对象:

x.clone() == x; 返回falsex.clone().getClass() == x.getClass(); 返回true

虽然通常情况下

x.clone().equals(x); 返回true

但这些并不是绝对的要求。

所有实现了Cloneable接口的类都应该用一个共有的方法覆盖Object的clone方法,并且在该clone方法内部应该先调用super.clone()方法,然后再修正需要调整的域。因为这样才可以递归调用到Object的clone方法,从而创建出正确的克隆。否则如果我们直接再clone方法里通过构造器创建对象,就可能得不到预期的类。

所有数组都被认为是实现了Cloneable接口,并且数组类型 T [] 的clone方法的返回类型是 T [],其中T可以是任何引用类型或原始类型。

深拷贝和浅拷贝

先看一段代码:

32f76c283fa11e49e087380878021479.png

clone示例

上面这个代码输出结果为:

Person@4554617c/Person@4554617c/Person@74a14482

可以看大,p1和p2输出相同,p3输出不同。下面来解释一下:

看过Java虚拟机的都知道,Java运行时数据区的概念。在这个例子里面,p1、p2、p3三个变量会在栈中创建,new出来的剑桥大学张三这个Person对象在Java堆中创建。代码中,p1和p2指向的是Java堆中的同一个对象,所以输出相同。但p1.clone()语句是在Java堆中克隆一个新的张三,并被p3引用,这是两个对象,所以p3输出不同于p1和p2。

知道了这个概念,那么什么是深拷贝什么是浅拷贝?

如果我们把上面的输出语句换成:

System.out.println(p1.getSchool()+"/"+p2.getSchool()+"/"+p3.getSchool());

那么看一下输出:

School@6bc168e5/School@6bc168e5/School@6bc168e5

p1、p2、p3输出的school对象信息都一样。这是因为Java执行的是浅拷贝。虽然我克隆了Person,但Person里面的School并没有克隆,仅仅是将拷贝对象里面的school引用指向了原new出来的Person对象创建的School。也就是默认克隆仅仅克隆本对象,本对象内部引用的其他对象,仅仅是传递引用,并没有为它们克隆新的实例。那么Java如何进行深拷贝呢?我只需要为School类添加clone方法并且修改Person类的clone方法即可,主函数中p1、p2、p3赋值关系不变:

35e5a57a08f68c17580b307f92c0837f.png

深拷贝

输出结果为:

School@4554617c/School@4554617c/School@74a14482

可以看出,p3的School也进行了拷贝。

如果School类中也组合了其他对象呢?如果需要深拷贝,School中组合的类也应该重写clone方法,并且在School类的clone方法中调用。也就是说这是一个clone调用链。如果想要进行完全深拷贝,必须保证这个clone调用链的完整。

其他文章:

为什么要重写equals方法和hashCode方法

如何理解清楚Java的抛出结构

Java泛型和通配符类型你真的能搞清楚吗

其实Java枚举类和普通类没什么区别

Java字符串:StringBuilder 和 StringBuffer

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值