Java Clone机制

1 什么是 Clone ,容易实现吗?

简单地说, Clone 就是对于给定的一个对象实例 o ,得到另一个对象实例 o’ : o 与 o’ 类

型相同( o.getClass() == o’.getClass() ),内容相同(对于 o/o’ 中的字段 f ,如果 f 是基本数据类型,则 o.f == o’.f ;如果 f 是对象引用,则 o.f == o’.f 或 o.f 指向的对象与 o’.f 指向的对象的内容相同)。通常称 o’ 为 o 的克隆或副本。

直观上看,似乎很容易为一个类加上 clone 方法:
class A {

private Type1 field1;

private Type2 field2;

…..

public Object clone() {

A a = new A();

a.field1 = a.getField1();

a.field2 = a.getField2();

……

return a;

}

}

然而,稍加推敲,就会发现这样的实现方法有两个问题:

1. 要想某个类有 clone 功能,必须单独为其实现 clone() 函数,函数实现代码与该类定义密切相关。

2. 即使基类 A 已有 clone() 函数,其子类 ExtendA 若要具备 clone 功能,则必须 override 其基类 A 的 clone() 函数。否则,对类型为 ExtendA 的对象 ea 的 clone() 方法的调用,会执行于类 A 中定义的 clone() 方法而返回一个类型为 A 的对象,它显然不是 ea 的克隆。
2 Java 对 clone 的支持

万类之初的 Object 类有 clone() 方法:

protected native Object clone() throws CloneNotSupportedException;

该方法是 protected 的,显然是留待被子类 override 的。该方法又是 native 的,必然做了

与具体平台相关的底层工作。

事实上,类 Object 的 clone() 方法首先会检查 this.getClass() 是否实现了 Cloneable 接口。

Cloneable 只是一个标志接口而已,用来标志该类是否有克隆功能。

public interface Cloneable {

}

如果 this.getClass() 没有实现 Cloneable 接口, clone() 就会抛 CloneNotSupportedException 返回。否则就会创建一个类型为 this.getClass() 的对象 other ,并将 this 各 field 的值赋值给 other 的对应 field ,然后返回 other 。

如此一来,我们要定义一个具有 Clone 功能的类就相当方便:

1. 在类的声明中加入“ implements Cloneable ”,标志该类有克隆功能;

2. Override 类 Object 的 clone() 方法,在该方法中调用 super.clone() :


class CloneableClass implements Cloneable {

……

public Object clone() {

try {

return super.clone(); // 直接让 Object.clone() 为我们代劳一切

} catch (CloneNotSupportedException e) {

throw new InternalError();

}

}

}

3 Shallow Clone 与 Deep Clone
3.1 Shallow 与 Deep 从何而来

一个具有克隆功能的类,如果有可变( Mutable )类类型的字段 field ,如何为其克隆(副

本)对象 o’ 中的 field 赋值?

方法一、如 Object 的 clone() 方法所实现:设原始对象为 o ,其克隆对象是 o’ ,执行 o’.field = o.field 。这样, o’.field 与 o.field 指向同一个可变对象 m 。 o 与 o’ 可能会相互影响(一个对象的状态可能会随着另一个对象的状态的改变而改变)。这样的 Clone 称为 Shallow Clone 。这也是 Object 的 clone() 方法的实现方式。

方法二、将 o.field 指向的可变对象 m 克隆,得到 m’ ,将 m’ 的引用赋值给 o’.field 。这样 o’ 与 o 内容相同,且相互之间无影响(一个对象状态的改变不会影响另一个对象的状态)。这样的 Clone 称为 Deep Clone 。

Java Collection 类库中具体数据结构类( ArrayList/LinkedList , HashSet/TreeSet , HashMap/TreeMap 等)都具有克隆功能,且都是 Shallow Clone ,这样设计是合理的,因为它们不知道存放其中的每个数据对象是否也有克隆功能。 System.arrayCopy() 的实现采用的也是 Shallow Clone 。

Deep Clone 对于实现不可变( Immutable )类很有帮助。设一个类包含可变类 M 类型的 field ,如何将其设计为不可变类呢?先为 M 实现 Deep Clone 功能,然后这样设计类 ImmutableClass :
class ImmutableClass {

MutableClass m;

ImmutableClass(MutableClass m) {

this.m = m.clone(); // 将传入的 m 的 clone 赋值给内部 m

}

public MutableClass getM() {

return this.m.clone(); // 将内部 m 的 clone 返回给外部

}

}

3.2 如何实现 Deep Clone

检查类有无可变类类型的字段。如果无,返回 super.clone() 即可;

如果有,确保包含的可变类本身都实现了 Deep Clone ;

Object o = super.clone(); // 先执行浅克隆,确保类型正确和基本类型及非可变类类型字段内容正确

对于每一个可变类类型的字段 field :

o.field = this.getField().clone();

返回 o 。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值