JAVASE每日加强一点点——对象的拷贝

77 阅读3分钟

对象的拷贝

创建一个Person对象 里面有两个属性 name 与 age

package arrayList.src.JavaSE.Study.Studay02;
​
public class Person {
    private String name;
    private int age;
    
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public int getAge() {
        return age;
    }
​
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }
}

在Test类中设置分别设置两个属性的值

Person person = new Person();
person.setName("小明");
person.setAge(23);

此时内存模型图为:

copy1.png

当再声明一个Person类型的对象,并且指向了同一块内存空间,并且重新设置一下他们的属性,此时内存模型的图为:

Person person1 = person;
person1.setAge(44);
person1.setName("小红");

copy2.png

从此图中我们可以分析得知,不仅仅刚刚声明对象的属性改了,一开始创建对象的属性也进行了更改。是不是这样呢?

Person person = new Person();
person.setName("小明");
person.setAge(23);
Person person1 = person;
System.out.println(person.hashCode());
System.out.println(person1.hashCode());
person1.setAge(44);
person1.setName("小红");
System.out.println(person1.toString());
System.out.println(person.toString());

coy3.png

为什么要用克隆(拷贝)

克隆的对象可能包含一些已经修改过的属性,而 new 出来的对象的属性都还是初始化时候的值,所以当需要一个新的对象来保存当前对象的“状态”就靠克隆方法了。

浅克隆

1:在类中实现Cloneable接口,重写clone()方法

package arrayList.src.JavaSE.Study.Studay02;
​
public class Person implements Cloneable {
    private String name;
    private int age;
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public int getAge() {
        return age;
    }
​
    public void setAge(int age) {
        this.age = age;
    }
​
    @Override
    protected Person clone() throws CloneNotSupportedException { //这里值得注意要改成Person类型默认是Object类型的
        return (Person) super.clone();
    }
​
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }
}
​

2、在新声明对象中直接指向克隆出来的引用

 Person person1 = person.clone();

再次重新设置属性并且输出当前对象的属性与之前 的对象的属性

        try {
                Person person1 = person.clone();
            person1.setName("小红");
            person1.setAge(45);
            System.out.println(person1.toString());
            System.out.println(person.toString());
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }

结果

copy4.png

此时内存模型的图为

copy5.png

深克隆(深拷贝)

上面所提到的深拷贝Person类中所有属性全为基本数据类型,可实际开发中一个实体类不可能只存在基本数据类型,但是存在引用数据类型该怎么办,此时就需要深拷贝

重新定义Person类name 、age属性再定义一个Water实类。

package arrayList.src.JavaSE.Study.Studay02;
​
public class Person implements Cloneable {
    private String name;
    private int age;
​
    private Water water;
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public int getAge() {
        return age;
    }
​
    public void setAge(int age) {
        this.age = age;
    }
​
    @Override
    protected Person clone() throws CloneNotSupportedException {
        return (Person) super.clone();
    }
​
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }
}

Water类

public class Water {
    private int WaterVolume = 40;   //水量
​
    public int getWaterVolume() {
        return WaterVolume;
    }
​
    @Override
    public String toString() {
        return "Water{" +
                "WaterVolume=" + WaterVolume +
                '}';
    }
​
    public void setWaterVolume(int waterVolume) {
        WaterVolume = waterVolume;
    }
}

Test类实例化water对象并设置属性值30;再声明为water1指向water设置属性50

public class Test {
    public static void main(String[] args) {
        Person person = new Person();
        Water water = new Water();
        water.setWaterVolume(30);
        person.setName("小明");
        person.setAge(23);
        person.setWater(water);
        try {
            Water water1 = water;
            water1.setWaterVolume(50);
            Person person1 = person.clone();
            person1.setName("小红");
            person1.setAge(45);
            person1.setWater(water1);
            System.out.println("拷贝后的:"+person1.toString());
            System.out.println("拷贝前的"+person.toString());
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }
}

此时运行结果:

copy6.png

发现,Water的值被改变了?

于是我们进行如下操作

再原有的Water类中实现Cloneable接口,实现返回Water类型clone方法,Test类修改为

 Water water1 = water.clone();

结果:

copy7.png

内存模型:

copy8.png