The difference between deep copy, shallow copy and reference copy

Table of contents

Author: Xiaoniu Hululu |  https://xiaoniuhululu.com
More exciting articles on computer internal skills, JAVA bottom layer, interview related information, etc. are available on the public account "Xiaoniuhululu"

copy by reference

Reference copy: Reference copy will not create a new object on the heap, but will only generate a new reference address on the stack, eventually pointing to the same object still on the heap .

//实体类
public class Person{
    public String name;//姓名
    public int height;//身高
    public StringBuilder something;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public StringBuilder getSomething() {
        return something;
    }

    public void setSomething(StringBuilder something) {
        this.something = something;
    }

    public Person(String name, int height, StringBuilder something) {
        this.name = name;
        this.height = height;
        this.something = something;
    }

}

//测试类
public class copyTest {
    public static void main(String[] args) {
        Person p1 = new Person("小张", 180, new StringBuilder("今天天气很好"));
        Person p2 = p1;

        System.out.println("对象是否相等:"+ (p1 == p2));
        System.out.println("p1 属性值=" + p1.getName()+ ","+ p1.getHeight() + ","+ p1.getSomething());
        System.out.println("p2 属性值=" + p2.getName()+ ","+ p2.getHeight() + ","+ p2.getSomething());


        // change
        p1.name="小王";
        p1.height = 200;
        p1.something.append(",适合出去玩");
        System.out.println("...after p1 change....");

        System.out.println("p1 属性值=" + p1.getName()+ ","+ p1.getHeight() + ","+ p1.getSomething());
        System.out.println("p2 属性值=" + p2.getName()+ ","+ p2.getHeight() + ","+ p2.getSomething());

    }
}

result:

Whether the objects are equal: true
p1 attribute value = Xiao Zhang, 180, the weather is good today
p2 attribute value = Xiao Zhang, 180, the weather is good today
...after p1 change....
p1 attribute value = Xiao Wang, 200, The weather is very good today, suitable for going out to play
p2 attribute value = Xiao Wang, 200, the weather is very good today, suitable for going out to play

before change:


after change:

We can see that since the two references p1 and p2 both point to the same object in the heap, the two objects are equal. Modifying the object p1 will affect the object p2, which needs
attention

  1. The name attribute, although it is a reference type, is also a String type, which is immutable. If it is modified, the JVM will create a new memory space on the heap by default, and then reassign the value
  2. int weight=180; yes成员变量,存放在堆中,不是所有的基本类型变量 都存放在JVM栈中

Note that it is different from this article.  Why is there only value passing in Java? ,  int num1 = 10;yes 基本类型的局部变量, stored on the stack

shallow copy

Shallow copy: Shallow copy creates a new object on the heap. The new object is not equal to the original object, but the properties of the new object are the same as the old object .
in:

  • If the attribute is a basic type (int, double, long, boolean, etc.), the value of the basic type is copied.
  • If the attribute is a reference type (except basic types are reference types), what is copied is the address value of the reference data type variable, and the object in the heap pointed to by the reference type variable will not be copied.

How to implement shallow copy? It is also very simple, that is, implement the Cloneable interface on the class that needs to be copied and rewrite its clone() method .

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

When using it, just call the clone() method of the class directly

//实体类 继承Cloneable
public class Person implements Cloneable{
    public String name;//姓名
    public int height;//身高
    public StringBuilder something;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public StringBuilder getSomething() {
        return something;
    }

    public void setSomething(StringBuilder something) {
        this.something = something;
    }

    public Person(String name, int height, StringBuilder something) {
        this.name = name;
        this.height = height;
        this.something = something;
    }



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

}

//测试类
public class shallowCopyTest {

    public static void main(String[] args) throws CloneNotSupportedException {
        Person p1 = new Person("小张", 180, new StringBuilder("今天天气很好"));
        Person p2 = p1.clone();

        System.out.println("对象是否相等:"+ (p1 == p2));
        System.out.println("p1 属性值=" + p1.getName()+ ","+ p1.getHeight() + ","+ p1.getSomething());
        System.out.println("p2 属性值=" + p2.getName()+ ","+ p2.getHeight() + ","+ p2.getSomething());


        // change
        p1.setName("小王");
        p1.setHeight(200);
        p1.getSomething().append(",适合出去玩");
        System.out.println("...after p1 change....");

        System.out.println("p1 属性值=" + p1.getName()+ ","+ p1.getHeight() + ","+ p1.getSomething());
        System.out.println("p2 属性值=" + p2.getName()+ ","+ p2.getHeight() + ","+ p2.getSomething());

    }
}

result:

Whether the objects are equal: false
p1 attribute value = Xiao Zhang, 180, the weather is fine today
p2 attribute value = Xiao Zhang, 180, the weather is fine today
...after p1 change....
p1 attribute value = Xiao Wang, 200, The weather is very good today, suitable for going out to play
p2 attribute value = Xiao Zhang, 180, the weather is very good today, suitable for going out to play

before change:


after change:

We can see that:

  1. When we modify the weight property of object p1, since the height property of p2 directly copies the height property of p1 before modification, it is still 180.
  2. When we modify the name attribute of the object p1, the String name points to a new memory space, but the name of the object p2 still points to the old memory space, so the name attribute of the object p2 is still "Xiao Zhang".
  3. Since the something property of object p1 and the something property of object p2 point to the same memory space, when we modify the something property of object p1, it will affect the something property of object p2, so the something property of object p2 becomes "the weather is fine today , suitable for hanging out".

deep copy

Deep copy: copy an object completely, create a new object on the heap, copy the value of the member variable of the copied object, and copy the object in the heap at the same time.
Need to override the clone method

    @Override
    public Person clone() throws CloneNotSupportedException {
        //return (Person) super.clone();
        Person person = (Person) super.clone();
        person.setSomething( new StringBuilder(person.getSomething()));//单独为引用类型clone
        return person;
    }

The results of the shallowCopyTest test class:

Whether the objects are equal: false
p1 attribute value = Xiao Zhang, 180, the weather is fine today
p2 attribute value = Xiao Zhang, 180, the weather is fine today
...after p1 change....
p1 attribute value = Xiao Wang, 200, The weather is very good today, suitable for going out to play
p2 attribute value = Xiao Zhang, 180, the weather is very good today

At this time, the object p1 and the object p2 do not interfere with each other.

before change:


After change:

But there is also a small problem. Every time an object has a reference type, we have to rewrite its clone method, which will be very troublesome, so we can also use serialization to achieve deep copying of objects

//实体类 继承Cloneable
public class Person implements Serializable{
    public String name;//姓名
    public int height;//身高
    public StringBuilder something;

...//省略 getter setter


    public Object deepClone() throws Exception{
        // 序列化
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
    
        oos.writeObject(this);
    
        // 反序列化
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
    
        return ois.readObject();
    }

}

//测试类,这边类名笔者就不换了,在之前的基础上改改
public class shallowCopyTest {

    public static void main(String[] args) throws Exception {
        Person p1 = new Person("小张", 180, new StringBuilder("今天天气很好"));
        Person p2 = (Person)p1.deepClone();

        System.out.println("对象是否相等:"+ (p1 == p2));
        System.out.println("p1 属性值=" + p1.getName()+ ","+ p1.getHeight() + ","+ p1.getSomething());
        System.out.println("p2 属性值=" + p2.getName()+ ","+ p2.getHeight() + ","+ p2.getSomething());


        // change
        p1.setName("小王");
        p1.setHeight(200);
        p1.getSomething().append(",适合出去玩");
        System.out.println("...after p1 change....");

        System.out.println("p1 属性值=" + p1.getName()+ ","+ p1.getHeight() + ","+ p1.getSomething());
        System.out.println("p2 属性值=" + p2.getName()+ ","+ p2.getHeight() + ","+ p2.getSomething());

    }
}

This will also result in a deep copy

summary

  1. Reference copy: Reference copy will not create a new object on the heap, but will only generate a new reference address on the stack, eventually pointing to the same object still on the heap .
  2. Shallow copy: Shallow copy creates a new object on the heap. The new object is not equal to the original object, but the properties of the new object are the same as the old object .

in:

  • If the attribute is a basic type (int, double, long, boolean, etc.), the value of the basic type is copied.
  • If the attribute is a reference type (except basic types are reference types), what is copied is the address value of the reference data type variable, and the object in the heap pointed to by the reference type variable will not be copied.
  1. Deep copy: copy an object completely, create a new object on the heap, copy the value of the member variable of the copied object, and copy the object in the heap at the same time.

Reference materials:
where int a = 1 is stored_ly_dsjing's blog-CSDN blog
In which memory area of ​​the jvm are the member variables of the basic data type placed? - huliangbin - Blog Garden
Thank you very much for reading to the end. If you like it, please follow, like, collect and forward, thank you! More great articles

Guess you like

Origin blog.csdn.net/weixin_45499836/article/details/126482694