如何实现 java clone ?

Java Clone

使用clone方法复制一个对象,clone对象拥有独立的地址。

实现clone的方式:

@Data
@ToString
class Father implements Cloneable { //1.clone的对象需要实现Cloneable接口
    private String name;
    private int age;

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

    @Override
    public Object clone() throws CloneNotSupportedException { //2.重写父类的clone()方法
        return super.clone();
    }
}

通常我们实现接口的时候会一并实现接口的方法,可是当我们 implements Cloneable 接口的时候,会发现Cloneable接口根本没有方法。

Q:clone方法是从哪里来的?

A:通过源码可以看到,clone()是基类Object的方法,所有对象默认继承Object,也就是说只要是对象就有clone方法。
clone()源码
那么,问题来了,既然基类有 clone() 方法,

Q:为什么要实现 Cloneable 接口?

A:从源码 clone() 注释可以看到,如果不实现 Cloneable 接口,则会抛出 CloneNotSupportedException 异常,那注释含义是否可以理解为,Cloneable 接口是作为可以clone对象的标识,标志着只有实现了Cloneable 接口的对象才可以克隆对象。

Q:克隆对象跟引用对象的区别?

A:
引用对象:通过对象A赋值得到一个引用对象B,A和B指向的是同一个地址,所以当改变任意一个的值,另一个也会随着改变。
克隆对象:A对象克隆一个对象B,A和B拥有独立的地址,任意改变一个值,另一个对象不会受影响。

测试 clone() 对象:

public class CloneTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        //引用对象
        Father a = new Father("a", 40); //初始化a对象
        Father b = a; //通过a赋值得到一个引用对象b
        b.setName("b"); //b对象改变name值为b
        System.out.println("a : " + a.toString() + " b : " + b.toString());
        //打印结果:a : Father(name=b, age=40)  b : Father(name=b, age=40)
        //通过结果发现,b对象改变name值,影响了a对象的name值,说明a和b指向同一地址

        //克隆对象
        a = new Father("a", 40); //初始化a对象
        b = (Father) a.clone(); //a克隆对象b
        b.setName("b"); //b对象改变name值为b
        System.out.println("a : " + a.toString() + " b : " + b.toString());
        //打印结果:a : Father(name=a, age=40)  b : Father(name=b, age=40)
        //通过结果发现,b对象改变name值,没有影响a对象,说明a和b拥有独立的地址
    }
}

Q:浅拷贝和深拷贝的区别?

A:
浅拷贝:对象无法clone包含的引用对象,clone() 默认浅拷贝。

@Data
@ToString
class Father implements Cloneable {
    private String name;
    private int age;
    private Child child; //新增child

    public Father(String name, int age, Child child) {
        this.name = name;
        this.age = age;
        this.child = child;
    }

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

@Data
@ToString
class Child {
    private String childName;

    public Child(String childName) {
        this.childName = childName;
    }
}

Father对象里面新增了一个Child对象。

浅拷贝代码测试:

public class CloneTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Father a = new Father("a", 40, new Child("a.a"));
        Father b = (Father) a.clone();
        b.getChild().setChildName("b.b");
        System.out.println("a == b : " + (a == b));
        //打印结果:a == b : false
        //结果表明实现了Cloneable的Father对象,拥有不同的地址
        System.out.println("a.child == b.child : " + (a.getChild() == b.getChild()));
        //打印结果:a.child == b.child : true
        //结果表明未实现Cloneable的Father.Child对象,即使父类实现了Cloneable,但是Father.Child对象指向的是同一个地址
        System.out.println("a : " + a.toString() + " \nb : " + b.toString());
        //打印结果:a : Father(name=a, age=40, child=Child(childName=b.b)) 
	   //		  b : Father(name=a, age=40, child=Child(childName=b.b))
        
    }
}

深拷贝:对象包含的引用对象同步clone。

@Data
@ToString
class Father implements Cloneable {
    private String name;
    private int age;
    private Child child; //1.新增child

    public Father(String name, int age, Child child) {
        this.name = name;
        this.age = age;
        this.child = child;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        Father father = (Father) super.clone();
        father.child = (Child) child.clone(); //3.Father接收Clone的Child对象
        return father;
    }
}

@Data
@ToString
class Child implements Cloneable { //2.Child实现Cloneable
    private String childName;

    public Child(String childName) {
        this.childName = childName;
    }

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

Child对象实现了Cloneable,Father对象里面新增了一个Child对象,Father继承的clone方法接收了clone对象。

深拷贝代码测试:

public class CloneTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Father a = new Father("a", 40, new Child("a.a"));
        Father b = (Father) a.clone();
        b.getChild().setChildName("b.b");
        System.out.println("a == b : " + (a == b));
        //打印结果:a == b : false
        System.out.println("a.child == b.child : " + (a.getChild() == b.getChild()));
        //打印结果:a.child == b.child : false
        //结果表明Father.Child对象也被clone
        System.out.println("a : " + a.toString() + " \nb : " + b.toString());
    }
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值