详细讲述Java中的克隆
经常听到有人说java中没有指针 事实如此吗?no java是有指针的 只不过换了个名字而已 也就是我们经常提到的引用 我们知道 在java中一切都是对象 那么我们如何操控对象?如何在成千上万的对象中找到我们所需的那个对象呢?又是如何让对象按照我们的意思来完成任务的呢?
Object o = new Object()
这是java中最常见的语句了 在这句话中做了三件事 首先声明一个Object类型的变量o 在内存中为对象划分一块地址new Object() 将声明的变量指向内存中的对象 如此一来 我们就可以通过o来操纵对象了 就好像孩子们玩的遥控飞机 在空中飞行的是飞机 而使它做出优美动作的却是孩子们手中的摇控器
克隆 是如今听到的较多的词汇 听说已经将某只羊克隆了好几份了 但愿这种技术不要在人身上实验 java中也有 克隆 与现实世界的克隆一样 将一个实际存在的对象拷贝几份 如下
//倒霉的羊public class Sheep implements Cloneable{private String name;public void setName(String arg) {name = arg;}public String getName() {return name;}public Object clone() throws CloneNotSupportedException {return super clone();}}//克隆public class Main {public static void main(String[] args) throws CloneNotSupportedException {Sheep sheep = new Sheep(); //先得到那只羊的实例sheep setName( 我是真的 ); //给它做个记号System out println( sheep getName() = + sheep getName());Sheep sheepClone = (Sheep)sheep clone(); //开始克隆System out println( sheepClone getName() = + sheepClone getName());}}
运行程序结果为
sheep getName() = 我是真的
sheepClone getName() = 我是真的
两只羊是一模一样的(哪怕那只羊瘸腿) 让我们来看看代码 首先要注意的是Sheep类实现了Cloneable接口(该接口属于java lang包 默认已经导入了) 该接口中并没有定义要实现的方法 是个空接口 起标志作用 也就是说 实现了这个接口的羊就不再是只普通的羊 它是一只可以被克隆的羊 再往下看 有个clone方法 返回Object类型的对象 并抛出CloneNotSupportedException异常 该方法覆写了父类 (Object)的clone方法 并在最后调用了super clone() 这也意味着无论clone类继承结构是什么样的 super clone ()都会直接或间接调用Object类的clone()方法 看看jdk帮助文档会发现 Object类的clone()是一个native方法 我们知道 native方法的效率一般来说都是远高于java中的非native方法 这也说明了new一个对象 然后将原对象中的数据导入到新创建的对象中去的做法是多么愚蠢 必须说明的是Object中的clone方法是protected的 所以要使用clone就必须继承Object类(默认) 并且为了可以使其它类调用该方法 必须将其作用域设置为public
以上只是一个简单clone的实现 明天说说 影子clone 和 深度clone
夜 深了 何为影子clone?先看一下例子
//倒霉的羊public class Sheep implements Cloneable{private String name;public void setName(String arg) {name = arg;}public String getName() {return name;}public Object clone() throws CloneNotSupportedException {return super clone();}}//羊圈public class Sheepfold implements Cloneable {public Sheep sheep;public String name;public Sheepfold() {sheep = new Sheep();}public Object clone() throws CloneNotSupportedException {return super clone();}}//克隆public class Main {public static void main(String[] args) throws Exception {Sheepfold fold = new Sheepfold();fold name = 小羊圈 ;fold sheep setName( 小羊 );Sheepfold fold = (Sheepfold)fold clone();System out println( fold name = + fold name);System out println( fold sheep getName() = + fold sheep getName());fold name = 大羊圈 ;fold sheep setName( 大羊 );System out println( ===================================== );System out println( fold name = + fold name);System out println( * fold sheep getName() = + fold sheep getName());System out println( fold name = + fold name);System out println( * fold sheep getName() = + fold sheep getName());System out println( ===================================== );}}
在这个例子中有三个类 Sheep和Sheepflod都实现了Cloneable接口 并且覆写了Object类的clone方法 说明这两个类是具有克隆能力的 注意一点 在Sheepflod中持有一个Sheep的实例 并在Main类中对其进行克隆 结果如下
fold<fp class='fp-3p43k'></fp><fp class='fp-6kh1w'></fp>name = 小羊圈fold<fp class='fp-3p43k'></fp><fp class='fp-szkq0'></fp>sheep<fp class='fp-6kh1w'></fp>getName() = 小羊=====================================fold<fp class='fp-4kby3'></fp><fp class='fp-5w0yq'></fp>name = 大羊圈* fold<fp class='fp-3p43k'></fp><fp class='fp-5w0yq'></fp>sheep<fp class='fp-y11o7'></fp>getName() = 大羊fold<fp class='fp-5w0yq'></fp>name = 小羊圈* fold<fp class='fp-y11o7'></fp>sheep<fp class='fp-5w0yq'></fp>getName() = 大羊=====================================
请注意一下结果中带有 * 号的两条结果语句 fold sheep和fold sheep的name都变为了 大羊 很奇怪是吗?在此之前 我们只对fold sheep的name赋过值 为什么fold sheep的name也变为了 大羊 呢?原因很简单 因为它们是指向同一个对象的不同引用 从中可以看出 调用Object类中clone()方法时 首先在内存中划分一块同原对象相同的空间 然后将原对象的内容原样拷贝至新对象 我们知道 java中有基本数据类型 对于基本数据类型 这样的操作是没有问题的 但对非基本类型变量 它们保存的仅仅是对象的引用 这也是为什么clone后非基本类型变量和原对象中的变量指向同一个对象的原因 可能你已经注意到 程序中用到了String类型 即对象 为什么没有出现引用指向同一地址的情况?这是因为String是一个不可更改的类(immutable class) 每次给它赋值时 都会产生一个新的String对象 如 String str = a str += b 在这两句代码中 当执行str += b 时 实际上是重新成生了一个值为 ab 的 String对象 即重新分配了一块内存空间 以上clone方法通常被称为 影子clone 影子clone 给我们留下了一个问题 即多个引用指向同一个对象 如何解决该问题呢?答案为 深度clone 把上面的例子改成深度clone很简单 只需将Sheepfold的clone()方法改为如下即可 很简单 只需将Sheepfold的clone()方法改为如下即可
public Object clone() throws CloneNotSupportedException {Sheepfold fold = (Sheepfold)super clone();sheep = (Sheep)fold sheep clone();return fold;}
lishixinzhi/Article/program/Java/gj/201311/27342