clone

传函数参数时的,传入基本类型  和 对象的效果是不一样的。  String对象的话 好像还有点特别,有待进一步实验验证 或者  查资料

影子clone    深度clone。

 

先看一下 clone的使用:

  1)类要实现Clonable接口,虽然这个接口中什么都没有

  2)在类中重写clone方法,因为Object中的clone接口是protect修饰的,所以在自己创建的类中需要重写这个方法,将其声明为public修饰,并且需要调用 Object的clone方法,这是一个 native本地方法。


public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
A a=new A();
a.setA(19);
System.out.println(a);
A clone = (A)a.clone();
System.out.println(clone.getA());
System.out.println(clone);
}
}
class A implements Cloneable{
int a=2; public int getA() { return a; }
public void setA(int a) { this.a = a; }
public A(){ System.out.println("A执行了构造函数"); }
@Override
public Object clone() throws CloneNotSupportedException { return super.clone(); } }

 

 

   可以看到,通过clone来创建对象是不会调用构造函数的,并且clone出来的对象和原来的对象不是同一个对象。那么对象是怎么被创建出来的呢?

影子克隆
clone是将引用地址传递过来了,还是新创建了一个新的实例,然后传递过来了?

  通过上面我们知道,通过clone方法创建A的实例时,是创建了一个新的A的实例,因为clone得到的实例与原来的实例的内存地址是不一样的,但是实例中的属性是重新创建的还是指向原来的地址呢?  通过下面这个例子,可以看出,对于基本类型是创建了一份复制,也就是clone后的实例修改实例中的基本类型的属性不会影响原来的实例中的数。但是,对于非基本类型呢,通过下面代码,我们发现是传来的与原对象实例相同的引用地址,那么修改clone后的对象的非基本类型的属性的值,会影响原来的对象实例。(注意:这里指的修改非基本类型的值,是修改非基本类型中的属性数据,而不是修改这个非基本类型的引用地址,因为只有两个引用指向了同一个地址,才会出现,一个对地址所指向的实例中属性数值的修改,另一个同样引用的,也会发生改变,因为地址指向是一样的)

public class CloneTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        A a=new A();
        a.setB(new B(22));
        a.setA(19);
        A clone = (A)a.clone();
        a.setA(00);
        a.getB().setB(11);
        System.out.println(a);
        System.out.println(clone);
    }
}

class A implements Cloneable{
    int a=2;
    B b;

    public B getB() {
        return b;
    }

    public void setB(B b) {
        this.b = b;
    }

    public int getA() {
        return a;
    }

    public void setA(int a) {
        this.a = a;
    }

    public A(){
        System.out.println("A执行了构造函数");
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "A{" +
                "a=" + a +
                ", b=" + b +
                '}';
    }
}

class B {
    int b=7;

    public B(int b) {
        System.out.println("调用了B的构造函数");
        this.b = b;
    }

    public int getB() {
        return b;
    }

    public void setB(int b) {
        this.b = b;
    }

    @Override
    public String toString() {
        return "B{" +
                "b=" + b +
                '}';
    }
}

 

 

  深度克隆

 那么,怎么让非基本类型的属性也不指向与原来对象一样的引用地址,就需要将这个对象也 实现 Cloneable 接口,重写它的 clone方法,这样就行了吗? 

  也就是在B类中也写一个这样的重载方法,并且B也实现Cloneable接口

  @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

【不经过自己深度思考获取的知识,不是自己的知识!】

  想一下,这样与上面那个例子,有什么区别? 好像只有B类多实现了一个接口,并且多写了一个clone重写方法。但是A在执行clone方法的时候,仍然会按照原来的方式进行,也就是并没有发生变化。clone后的属性b与原来的a实例指向的b,仍然是同一个。如果想让它不是同一个,就需要改变它的指向,也就是在A的clone方法中改变属性b的引用。怎么做? 调用B的clone方法。(当然你也可以选择重新new 一个B, 也可以选择通过反射来创建一个新的B,到那时它们的效率不要低于clone方式)

  修改A的clone方法:

  @Override
    public Object clone() throws CloneNotSupportedException {
        A clone = (A)super.clone();  // 得到 A的clone实例
        clone.b=(B)b.clone();   // 修改clone后的 A实例的 b属性  (将B也clone了一下)    这里要注意一点,要调用B实例的clone方法,要保证A中的b属性不是null
        return clone;
    }

 

 

   这时,可以看到 clone后的A的实例与原来的A的实例指向的属性b已经不是同一个了。

 

!!!   如果在A中有一个String类型的属性呢

class A implements Cloneable{
int a=2;
B b;
String c="sss";

public String getC() {
return c;
}

public void setC(String c) {
this.c = c;
}
..... 省略掉其它代码
}

 

public class CloneTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        A a=new A();
        a.setB(new B(22));
        a.setA(19);
        A clone = (A)a.clone();
        a.setA(00);
        a.getB().setB(11);
        a.setC("cccc");
        System.out.println(a);
        System.out.println(clone);
    }
}

 

   可以看到,colone前后的a实例的c属性指向的地址是不一样的,可以我们没有写他的clone方法啊,当然我们也写不了,因为String类是一个final修饰的类,那么这是怎么回事呢??

  这很正常,因为调用 setC(String c)方法,就是传入的一个新的对象c , 并把c的地址赋给了实例a中的 c属性。不止是String类型的,任何类型的都是这样。

【只有真正理解,才能真正理解】

 

参考文档:

这篇写的挺好的: https://www.cnblogs.com/shoshana-kong/p/10820420.html

posted @ 2020-07-13 10:33  你眼里的星辰  阅读(542)  评论(0)    收藏  举报