Clonable 接口和深拷贝

Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 “拷贝”.
Clonable 接口和深拷贝_第1张图片

想用clone方法时报错了,查看一下:
在这里插入图片描述

  • clone方法被protected修饰.不同包只能在子类中访问,可以用super关键字访问
  • clone方法返回类型是Object,所以需要向下转型
  • CloneNotSupportedException是受查异常,所以调用它的方法不处理就要throws,main方法不处理就交给JVM处理了

改良的代码

class Person {
    public String name;

    public Person(String name) {
        this.name = name;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1 = new Person("张三");
        Person person2 = (Person)person1.clone();
        System.out.println(person2.name);
    }
}

但还是会报错
在这里插入图片描述
要想合法调用 clone 方法, 必须先实现 Clonable 接口, 否则就会抛出 CloneNotSupportedException 异常,而它是空的,没有需要重写的方法
Clonable 接口和深拷贝_第2张图片
如果一个类实现了这个空接口/标记接口,那么证明当前类是可以被克隆的

class Person implements Cloneable{
    public String name;

    public Person(String name) {
        this.name = name;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1 = new Person("张三");
        Person person2 = (Person)person1.clone();
        System.out.println(person2.name);
    }
}

在这里插入图片描述
可以用try-catch进行处理,这样就不必用throws将异常报告给抛出异常方法的调用者

class Person implements Cloneable {
    public String name;

    public Person(String name) {
        this.name = name;
    }

    @Override
    public Person clone() {
        Person person = null;
        try {
            person = (Person) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return person;
    }
}
public class Test {
    public static void main(String[] args) {
        Person person = new Person("张三");
        Person person2 = person.clone();
        System.out.println(person2.name);
    }
}

Clonable 接口和深拷贝_第3张图片

浅拷贝和深拷贝

Cloneable 拷贝出的对象是一份 “浅拷贝”

class Money {
    public double money = 13;
}
class Person implements Cloneable{
    public String name;
    public Money m;

    public Person(String name) {
        this.name = name;
        m = new Money();
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1 = new Person("张三");
        Person person2 = (Person)person1.clone();
        System.out.println("修改之前:"+person1.m.money);
        System.out.println("修改之前:"+person2.m.money);

        person2.m.money = 99;
        
        System.out.println("修改之后:"+person1.m.money);
        System.out.println("修改之后:"+person2.m.money);
    }
}

Clonable 接口和深拷贝_第4张图片

我们只修改了person2 的money,但person1的money也被改成了99.

内存分布大致是这样的
假设0x56,0x87指向引用地址的对象

Clonable 接口和深拷贝_第5张图片
我们可以看到,通过clone,我们只是拷贝了Person对象。但是Person对象中的Money对象并
没有拷贝。通过person2这个引用修改了m的值后,person1这个引用访问m的时候,值也发生了改变。这里就是发生了浅拷贝
改完后person1和person2还是指向同一个m,因为改变基本数据类型不会创建新的对象.

深拷贝是克隆出一个完全独立于原来对象的对象(如果类中有基本数据类型那就进行拷贝)

代码如下:

class Money implements Cloneable{
    public double money = 13;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
class Person implements Cloneable{
    public String name;
    public Money m;

    public Person(String name) {
        this.name = name;
        m = new Money();
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person tmp = (Person) super.clone();
        tmp.m = (Money)this.m.clone();
        return tmp;
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1 = new Person("张三");
        Person person2 = (Person)person1.clone();
        System.out.println("修改之前:"+person1.m.money);
        System.out.println("修改之前:"+person2.m.money);

        person2.m.money = 99;

        System.out.println("修改之后:"+person1.m.money);
        System.out.println("修改之后:"+person2.m.money);
    }
}

Clonable 接口和深拷贝_第6张图片
Clonable 接口和深拷贝_第7张图片
是不是深拷贝,就看程序猿实现的方式怎么样

你可能感兴趣的:(Java,java)