clone的使用来龙去脉

版权声明:转载请申明出处,谢谢 https://blog.csdn.net/qq_35495763/article/details/81321242

Cloneable接口
clone:

它允许在堆中克隆出一块和原对象一样的对象,并将这个对象的地址赋予新的引用。

Java 中 一个类要实现clone功能 必须实现 Cloneable接口,否则在调用 clone() 时会报 CloneNotSupportedException 异常。

Java中所有类都默认继承java.lang.Object类,在java.lang.Object类中有一个方法clone(),这个方法将返回Object对象的一个拷贝。
要说明的有两点:

一是拷贝对象返回的是一个新对象,而不是一个引用;
二是拷贝对象与用 new操作符返回的新对象的区别就是这个拷贝已经包含了一些原来对象的信息,而不是对象的初始信息。

如果一个类重写了 Object 内定义的 clone()方法 ,需要同时实现 Cloneable 接口(虽然这个接口内并没有定义 clone() 方法),否则会抛出异常,也就是说, Cloneable 接口只是个合法调用 clone() 的标识(marker-interface)。

实例

class CloneClass implements Cloneable{
 public int aInt;
 public Object clone(){
  CloneClass o = null;
  try{
   o = (CloneClass)super.clone();
  }catch(CloneNotSupportedException e){
   e.printStackTrace();
  }
  return o;
 }
}

有三个值得注意的地方:
一是为了实现clone功能,CloneClass类实现了Cloneable接口,这个接口属于java.lang 包,java.lang包已经被缺省的导入类中,所以不需要写成java.lang.Cloneable;
二是重载了clone()方 法;
三是在clone()方法中调用了super.clone(),这也意味着无论clone类的继承结构是什么样的,super.clone()直接或 间接调用了java.lang.Object类的clone()方法。

Object类的clone()方法是一个native方法,native方法的效率一般来说都是远高于java中的非native方法。这也解释了为 什么要用Object中clone()方法而不是先new一个对象,然后把原始对象中的信息赋到新对象中,虽然这也实现了clone功能,但效率较低。

Object类中的clone()方法还是一个protected属性的方法。这也意味着如果要应用clone()方法,必须继承Object类,在 Java中所有的类是缺省继承Object类的,也就不用关心这点了。

然后重载clone()方法。还有一点要考虑的是为了让其它类能调用这个clone 类的clone()方法,重载之后要把clone()方法的属性设置为public。

什么是mixin (混合类型)接口:类除了可以实现基本类型的接口。还可以实现一些提供可供选择的行为接口。一些任意选择的接口可以混合到类型的主要功能中。(一些次要接口功能,可供其他功能调用)
这里写图片描述
clone 实现原理:
如何一个类实现了cloneable 接口,object的clone()就返回该对象的逐域拷贝。
这里写图片描述
clone实现拷贝的含义是
这里写图片描述
1.返回的地址(对象地址不同)
2.类的类型信息(getCLASS返回这个对象运行时的类型信息的类cLass(存储类的类型信息的类))相同。
3.内容相同。

实现方式
注意点:还要知道的是除了基本数据类型能自动实现深度clone以外,String对象是一个例外,它clone后的表现好象也实现了深度clone,虽然这只是一个假象,但却大大方便了我们的编程

package Pack;
public class test implements Cloneable {
    private String name;
    private int age;

    test(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Object clone() {
        test o = null;
        try {
            // Object中的clone()识别出你要复制的是哪一个对象。
            o = (test) super.clone();
        } catch (CloneNotSupportedException e) {
            System.out.println(e.toString());
        }
        return o;
    }

    public static void main(String[] args) {
        test s1 = new test("zhangsan", 18);
        test s2 = (test) s1.clone();
        s2.name = "lisi";
        s2.age = 20;
        //修改学生2后,不影响学生1的值。
        System.out.println("name=" + s1.name.hashCode()+ "," + "age=" + s1.age);
        System.out.println("name=" + s2.name.hashCode() + "," + "age=" + s2.age);
    }
}
结果是:
name=-1432604556,age=18
name=3322003,age=20

JDK中StringBuffer类型,关于StringBuffer的说明,StringBuffer没有重载clone()方法,更为严重的是StringBuffer还是一个 final类,这也是说我们也不能用继承的办法间接实现StringBuffer的clone。如果一个类中包含有StringBuffer类型对象或和 StringBuffer相似类的对象,我们有两种选择:要么只能实现影子clone,要么就在类的clone()方法中加一句(假设是 SringBuffer对象,而且变量名仍是p): o.p = new StringBuffer(p.toString()); //原来的是:o.p = (DeepProfessor) p.clone();

浅复制的实现:

ackage com.king.cloneable;
/**
 * 浅复制2
 */
public class ShallowStudent2 implements Cloneable {
    String name;// 常量对象。
    int age;
    Professor p;// 学生1和学生2的引用值都是一样的。

    ShallowStudent2(String name, int age, Professor p) {
        this.name = name;
        this.age = age;
        this.p = p;
    }

    public Object clone() {
        ShallowStudent2 o = null;
        try {
            o = (ShallowStudent2) super.clone();
        } catch (CloneNotSupportedException e) {
            System.out.println(e.toString());
        }
        return o;
    }

    public static void main(String[] args) {
        Professor p = new Professor("wangwu", 50);
        ShallowStudent2 s1 = new ShallowStudent2("zhangsan", 18, p);
        ShallowStudent2 s2 = (ShallowStudent2) s1.clone();
        s2.p.name = "lisi";
        s2.p.age = 30;
        System.out.println("name=" + s1.p.name + "," + "age=" + s1.p.age);
        System.out.println("name=" + s2.p.name + "," + "age=" + s2.p.age);
        //输出结果学生1和2的教授成为lisi,age为30。
    }
}

class Professor {
    String name;
    int age;

    Professor(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

深复制的实现

package com.king.cloneable;

/**
 * 深复制
 */
public class DeepStudent implements Cloneable {
    String name;// 常量对象。
    int age;
    DeepProfessor p;// 学生1和学生2的引用值都是一样的。

    DeepStudent(String name, int age, DeepProfessor p) {
        this.name = name;
        this.age = age;
        this.p = p;
    }

    public Object clone() {
        DeepStudent o = null;
        try {
            o = (DeepStudent) super.clone();
            //对引用的对象也进行复制
            o.p = (DeepProfessor) p.clone();
        } catch (CloneNotSupportedException e) {
            System.out.println(e.toString());
        }
        return o;
    }

    public static void main(String[] args) {
        DeepProfessor p = new DeepProfessor("wangwu", 50);
        DeepStudent s1 = new DeepStudent("zhangsan", 18, p);
        DeepStudent s2 = (DeepStudent) s1.clone();
        s2.p.name = "lisi";
        s2.p.age = 30;
        System.out.println("name=" + s1.p.name + "," + "age=" + s1.p.age);
        System.out.println("name=" + s2.p.name + "," + "age=" + s2.p.age);
        //输出结果学生1和2的教授成为lisi,age为30。
    }
}

class DeepProfessor implements Cloneable {
    String name;
    int age;

    DeepProfessor(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Object clone() {
        DeepProfessor o = null;
        try {
            o = (DeepProfessor)super.clone();
        } catch(CloneNotSupportedException e) {
            System.out.println(e.toString());
        }
        return o;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_35495763/article/details/81321242