Java底层学习(五)——Object中的clone()方法详解

1、clone()方法概述

最近在学习《码出高效》这本书的时候关于Object中的clone()方法书中提及对象clone方法是浅拷贝,如果想使用深拷贝需要覆写clone()方法实现域对象的深度遍历式拷贝,于是我就总结了一些关于clone方法的问题。
在这里插入图片描述
注意:方法native表明实现方法的程序设计语言不是Java。clone方法前使用native关键字约束表示需要使用本地计算机语言或C语言访问硬件,这些方法标记为native。 native方法可以是终极的、公用的、
私有的、保护的、重载的或者覆盖的。
clone方法基本的作用就是拷贝对象,我们如果使用newObject=someObject方法来进行赋值,那么我们的到的只是简单的讲SomeObject的地址赋给了newObject,要创建一个新的单独内存空间的新对象,那么久需要使用clone()方法,如下所示:
newObject=someObject.clone();
这个语句讲someObject地址复制到一个新的内存地址,之后将新地址的引用赋值给了newObject。
还有一点需要注意的是不是所有对象都可以进行复制,如果要成为一个可复制的对象那么该类必须实现java.lang.Cloneable接口。、
若要声明一个实现Cloneable接口的自定义类,该类必须覆盖Object类中的clone()方法。

2、关于浅复制与深复制

来举一个《Java程序设计语言》中的例子:
克隆操作JVM内部流程图
首先我们调用了house2=house1.clone(),目的是想克隆house1中的所有数据到house2中,那么在实际执行过程中,域中的数据如果是基本数据类型,那么复制的是值,像id和area字段复制的是值。如果域中是一个对象,那么复制的会是域的引用,如whenBuilt的类型是Date类,所以他的引用被复制到了house2中。所以尽管house1==house2不为真,但是house1.whenBuilt==house2.whenBuilt为真,这种复制类型叫做浅复制。浅复制指的是如果复制域中是一个对象而不是基本数据类型,那么我们复制的是此类的引用而不是对象本身。
那么深复制指的就是复制过程中复制的是整个对象,而不是域内容的引用,我们在需要实现深复制的时候需要自定义复制操作覆盖clone方法,而不能简单的调用clone()方法来实现克隆。
注意!!!
假如没有覆写clone方法,程序会生成一个语法错误,如果复制的类没有实现java.lang.Cloneable接口,在类中直接调用super.clone()方法,那么将会引起CloneNotSupportException异常。因此如果需要实现对象的复制必须覆写clone()方法并实现java.lang.Cloneable接口。
每当编写方法或者构造器时,如果它要允许客户提供的对象进入到内部数据结构中,有必要考虑下客户提供的对象是否有可能是可变的。如果是,就考虑类是否能容忍这种变化,如果答案是否定的,则需要进行必要进行保护性拷贝,并且让拷贝之后的对象而不是原始对象进入数据结构中。
在内部组件被返回给客户端之前,不管类是否为不可变,在把一个指向内部可变组件的引用返回给客户端之前,应该返回保护性拷贝。长度非零的数组总是可变的。因此,在把内部数组返回给客户端之前,应该总是要进行保护性拷贝。
简而言之,如果类是不可变的,一般不需要进行保护性拷贝。若类具有从客户端得到或者返回到客户端的可变组件,类就必须保护性地拷贝这些组件。如果拷贝成本受到限制,并且类信任客户端不会不恰当地修改组件,就可以在文档中指明客户端的职责是不得修改受到影响的组件,以此来代替保护性拷贝。
总之,所有实现了Cloneable接口的类都应该用一个公有的方法覆盖clone方法。此方法首先调用super.clone,然后修正任何需要修正的域。一般情况下,这意味着要拷贝任何包含内部“深层结构”的可变对象,并用指向新对象的引用代替原来指向这些对象的引用。如果该类只包含基本类型的域,或者指向不可变对象的引用,那多半的情况下是没有域需要修正的。
其实实现Cloneable接口具有很多问题,很多接口都不应该扩展这个接口,也不应该实现这个接口。因此很多程序员从来不去覆盖clone方法,也从来不去调用它,除非拷贝数组。所以,慎重选择覆盖clone()方法。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值