目录

Object.clone()方法

如何使用

浅拷贝

深拷贝

如何实现深拷贝

Object.clone()方法

clone()是Object类中的方法可以拷贝出一个和调用者完全相同的方法,在Object类中,定义如下:

//拥有native关键字,说明是让底层C++来帮我们实现的,需要通知操作系统协助我们,也就是系统调用。
//使用了protected修饰,子类无法继承
protected native Object clone() throws CloneNotSupportedException;

如何使用

想要使用clone方法,必须自己主动重写,并且,重写的类必须实现Cloneable接口,例如

class A implements Cloneable {

    int a;
    String name;
    B bb;
    String[] arrs ;

    public A(){}
    public A( int a,  String name ){
        this.a = a;
        this.name = name;
        arrs = new String[2];
        arrs[0] = "金轮";
        arrs[1] = "起飞";
    }

    //主动重写clone方法,由于使用了系统调用,我们无法主动设定内容,只能调用Object的clone()
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "A{" +
            "a=" + a +
            ", name='" + name + '\'' +
            ", bb=" + bb +
            ", arrs=" + Arrays.toString(arrs) +
            '}';
    }
}

用以下代码作为验证克隆结果

A a = new A(120 , "芜湖大司马");
B bb = new B("芜湖飞机场");
a.bb = bb;
A b = (A)a.clone();
System.out.println(a);
System.out.println(b);
System.out.println(a == b);

//控制台输出
A{a=120, name='芜湖大司马', bb=B@7f31245a, arrs=[金轮, 起飞]}
A{a=120, name='芜湖大司马', bb=B@7f31245a, arrs=[金轮, 起飞]}
false
    
//B类
class B {
    String add;
    public B( String add ){
        this.add = add;
    }
}

可以看到,确实复制了属性一模一样的对象,但是地址并不相同。它们的内存空间是不一样的。

但是仔细观察!

//哎?这两个对象中的这个B类对象为什么是同一个?
bb=B@7f31245a
bb=B@7f31245a

浅拷贝

浅拷贝就是,通过clone方法,开辟一块新的内存空间,将原对象的基本数据类型和字符串(int,double,String...)直接拷贝一份新的赋值给新对象。将引用数据类型直接指向原对象使用的对象

结构图如下:

java 实现 Redis SSL_java

直接重写Object的clone()方法,只能实现浅拷贝

//只能实现浅拷贝
@Override
protected Object clone() throws CloneNotSupportedException {
    return super.clone();
}

测试一下

A a = new A(120 , "芜湖大司马");
B bb = new B("芜湖飞机场");
a.bb = bb;
A b = (A)a.clone();
System.out.println(a);
System.out.println(b);
System.out.println(a == b);
//修改拷贝对象的String
b.name = "芜湖";
//直接重新new一个B给拷贝对象
b.bb = new B("芜湖停车场");
//修改一下拷贝对象的arrs[1]
b.arrs[1] = "田赋";
System.out.println(a);
System.out.println(b);

//控制台打印
A{a=120, name='芜湖大司马', bb=B@7f31245a, arrs=[金轮, 起飞]}
A{a=120, name='芜湖大司马', bb=B@7f31245a, arrs=[金轮, 起飞]}
false
A{a=120, name='芜湖大司马', bb=B@7f31245a, arrs=[金轮, 田赋]}
//name不影响,bb的指向被修改,arrs由于是浅拷贝,两者使用的是同一个对象,所以修改拷贝对象会影响原对象
A{a=120, name='芜湖', bb=B@6d6f6e28, arrs=[金轮, 田赋]}

//A类
class A implements Cloneable {

    int a;
    String name;
    B bb;
    String[] arrs ;

    public A(){}
    public A( int a,  String name ){
        this.a = a;
        this.name = name;
        arrs = new String[2];
        arrs[0] = "金轮";
        arrs[1] = "起飞";
    }

    //主动重写clone方法,由于使用了系统调用,我们无法主动设定内容,只能调用Object的clone()
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "A{" +
            "a=" + a +
            ", name='" + name + '\'' +
            ", bb=" + bb +
            ", arrs=" + Arrays.toString(arrs) +
            '}';
    }
}

class B {
    String add;
    public B( String add ){
        this.add = add;
    }
}

由上述代码可以看出,确实是浅拷贝。

深拷贝

深拷贝指的是,在通过clone()方法拷贝对象时,无论是基本数据类型还是引用数据类型都会复制出一个新的对象来,生成两个从头到尾都不相同的对象

java 实现 Redis SSL_开发语言_02

如何实现深拷贝

让所有引用数据类型的类都实现clone()方法是实现不了的。

需要在A类中拓展clone方法。

核心观念:对引用数据类型进行生成新对象并改变引用,也就是手动拷贝引用数据类型

//在A的clone方法中不直接返回super.clone的结果
//返回前对其中的引用数据类型进行new新对象或者也进行clone
//由于引用数据类型是自己实现的,所以可以这么写
@Override
protected Object clone() throws CloneNotSupportedException {
    A na = (A) super.clone();
    na.bb = new B(bb.add);
    na.arrs = Arrays.copyOf(na.arrs,na.arrs.length);
    return na;
}

//或者
//套娃,让其中的引用数据类型也重新赋值为clone();
@Override
protected Object clone() throws CloneNotSupportedException {
    A na = (A) super.clone();
    na.bb = na.bb.clone();
    na.arrs = Arrays.copyOf(na.arrs,na.arrs.length);
    return na;
}

这样修改之后,再次运行代码,控制台打印就变了

b.name = "芜湖";
b.bb.add = "芜湖停车场";
b.arrs[1] = "田赋";
System.out.println(a);
System.out.println(b);

//可见修改值并不会影响原数组了,拷贝成功
A{a=120, name='芜湖大司马', bb=B{add='芜湖飞机场'}, arrs=[金轮, 起飞]}
A{a=120, name='芜湖', bb=B{add='芜湖停车场'}, arrs=[金轮, 田赋]}