Analysis of Java's deep copy and shallow copy from the perspective of memory

Shallow copy means that when copying an object, only the object itself (including the basic variables in the object) is copied, not the object pointed to by the reference contained in the object. Deep copy not only copies the object itself, but also all objects pointed to by the references contained in the copy object. For example, it is clearer: Object A1 contains a reference to B1, and B1 contains a reference to C1. A shallow copy of A1 gets A2, A2 still contains a reference to B1, and B1 still contains a reference to C1. Deep copy is the recursion of shallow copy, deep copy A1 gets A2, A2 contains a reference to B2 (copy of B1), and B2 contains a reference to C2 (copy of C1).

Next, use memory analysis to illustrate the difference between deep copy and shallow copy. Since this article focuses on the difference between the two copies, only the objects in the heap are analyzed during memory analysis.

Shallow copy

class House implements Cloneable{
	int size;
	String address;
	
	public House(int size, String address) {
		this.size = size;
		this.address = address;
	}

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

class Person implements Cloneable{
	String name;
	int age;
	House house;
	
	public Person(String name, int age, House house) {
		this.name = name;
		this.age = age;
		this.house = house;
	}
	
	public Person clone() {
		Person o = null;
		try {
			o = (Person)super.clone();
		}catch(Exception e) {
			System.out.println(e);
		}
		return o;
	}
}
public class CloneTest {
	public static void main(String[] args) {
		House house1 = new House(50, "平凡花苑");
		Person person1 = new Person("Xiaoming", 20, house1);
		System.out.println("改变前:" + "person1.name:" + person1.name + "  person1.age:" + person1.age + "  person1.house.size:" + person1.house.size + "  person1.house.address:" + person1.house.address);
		Person person2 = person1.clone();
		person2.name = "Meimei";
		person2.age = 30;
		
		//标记处
		person2.house.size = 80;
		person2.house.address = "梦想花苑";
		System.out.println("改变后:" + "person1.name:" + person1.name + "  person1.age:" + person1.age + "  person1.house.size:" + person1.house.size + "  person1.house.address:" + person1.house.address);
	}
}
// 改变前:person1.name:Xiaoming  person1.age:20  person1.house.size:50  person1.house.address:平凡花苑
// 改变后:person1.name:Xiaoming  person1.age:20  person1.house.size:80  person1.house.address:梦想花苑

 Before the mark

House house1 = new House(50, "平凡花苑");

The address starting with Ox represents the address of the object in the heap. First, a new house1 object is created. Since the attributes of the house object are all basic types, there is no arrow pointing to other objects.

Person person1 = new Person("Xiaoming", 20, house1);

When creating person1, because one of the member variables of the object is a reference variable, the address of house1 is stored in person1 (so the modification of the member variable of house1 is actually done outside the variable of person1) 

Person person2 = person1.clone();

The person2 created by the person1.clone() method has all the basic types of member variables of person1. Because the Object.clone method is a shallow copy method, it is impossible to copy the member variables of the reference type at the same time, so the house in person2 is still Save the memory address of the original house1

person2.name = "Meimei";
person2.age = 30;

The ordinary type variables in person2 have been completely separated from person1, so person2.name and person2.age will change after the above modification

After the mark

person2.house.size = 80;
person2.house.address = "梦想花苑";

At this time, person1 and person2 point to the same house1, so if you modify the member variable of house1 in person2, the member variable of house1 in person1 will also change accordingly.

Deep copy

class House implements Cloneable{
	int size;
	String address;
	
	public House(int size, String address) {
		this.size = size;
		this.address = address;
	}

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

class Person implements Cloneable{
	String name;
	int age;
	House house;
	
	public Person(String name, int age, House house) {
		this.name = name;
		this.age = age;
		this.house = house;
	}
	
	public Person clone() throws CloneNotSupportedException { //改变
		Person o = null;
		try {
			o = (Person)super.clone();
		}catch(Exception e) {
			System.out.println(e);
		}
		o.house = (House) house.clone();  //主要改变
		return o;
	}
}
public class CloneTest {
	public static void main(String[] args) throws CloneNotSupportedException { //改变
		House house1 = new House(50, "平凡花苑");
		Person person1 = new Person("Xiaoming", 20, house1);
		System.out.println("改变前:" + "person1.name:" + person1.name + "  person1.age:" + person1.age + "  person1.house.size:" + person1.house.size + "  person1.house.address:" + person1.house.address);
		Person person2 = person1.clone();
		person2.name = "Meimei";
		person2.age = 30;
		
		//标记处
		person2.house.size = 80;
		person2.house.address = "梦想花苑";
		System.out.println("改变后:" + "person1.name:" + person1.name + "  person1.age:" + person1.age + "  person1.house.size:" + person1.house.size + "  person1.house.address:" + person1.house.address);
	}
}
//  改变前:person1.name:Xiaoming  person1.age:20  person1.house.size:50  person1.house.address:平凡花苑
//  改变后:person1.name:Xiaoming  person1.age:20  person1.house.size:50  person1.house.address:平凡花苑

Before the mark 

House house1 = new House(50, "平凡花苑");
Person person1 = new Person("Xiaoming", 20, house1);
Person person2 = person1.clone();
person2.name = "Meimei";
person2.age = 30;

 The above code is basically the same as the shallow copy, so I don’t need to describe it too much, mainly observe the following differences

o.house = (House) house.clone();  //主要改变

 Compared with shallow copy, deep copy has one more line of code, similar to person1.clone(), because house has only basic types of variables, so house.clone can be copied completely, and the house2 obtained at this time has nothing to do with house1.

After the mark 

person2.house.size = 80;
person2.house.address = "梦想花苑";

Since person2 and the house2 it points to have nothing to do with the prototype (person1 and house1), any operations on house at this time will not affect house1 in person1

expand

Through the above introduction, everyone should be able to understand the difference between deep copy and shallow copy. Essentially, deep copy not only copies the object itself, but also all the objects pointed to by the references contained in the copied object, that is to say, the two objects obtained by deep copy do not have any intersection. In order to deepen our impression, we continue to introduce a tv variable, which is a reference variable in house1, through which person1 and person2 establish contact again

class House implements Cloneable{
	int size;
	String address;
	TV tv;  //增加一个tv类
	
	public House(int size, String address, TV tv) {  //改变构造方法
		this.size = size;
		this.address = address;
		this.tv = tv;
	}

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

//增加一个TV类
class TV{
	int size;
	String brand;
	
	public TV(int size, String brand) {
		this.size = size;
		this.brand = brand;
	}
}

class Person implements Cloneable{
	String name;
	int age;
	House house;
	
	public Person(String name, int age, House house) {
		this.name = name;
		this.age = age;
		this.house = house;
	}
	
	public Person clone() throws CloneNotSupportedException { //改变
		Person o = null;
		try {
			o = (Person)super.clone();
		}catch(Exception e) {
			System.out.println(e);
		}
		o.house = (House) house.clone();  
		return o;
	}
}
public class CloneTest {
	public static void main(String[] args) throws CloneNotSupportedException { //改变
		TV tv = new TV(65, "SONY");    //添加一个tv对象
		House house1 = new House(50, "平凡花苑", tv);  //改变
		Person person1 = new Person("Xiaoming", 20, house1);
		System.out.println("改变前:" + "person1.name:" + person1.name + "  person1.age:" + person1.age + "  person1.house.size:" + person1.house.size + "  person1.house.address:" + person1.house.address + "  person1.house.tv.size:" + person1.house.tv.size + "  person1.house.tv.brand:" + person1.house.tv.brand);  //改变
		Person person2 = person1.clone();
		person2.name = "Meimei";
		person2.age = 30;
		person2.house.size = 80;
		person2.house.address = "梦想花苑";
		
		//标记处
		person2.house.tv.size = 90;   //添加
		person2.house.tv.brand = "Xiaomi"; //添加
		System.out.println("改变后:" + "person1.name:" + person1.name + "  person1.age:" + person1.age + "  person1.house.size:" + person1.house.size + "  person1.house.address:" + person1.house.address + "  person1.house.tv.size:" + person1.house.tv.size + "  person1.house.tv.brand:" + person1.house.tv.brand);
	}
}
//  改变前:person1.name:Xiaoming  person1.age:20  person1.house.size:50  person1.house.address:平凡花苑  person1.house.tv.size:65  person1.house.tv.brand:SONY
//  改变后:person1.name:Xiaoming  person1.age:20  person1.house.size:50  person1.house.address:平凡花苑  person1.house.tv.size:90  person1.house.tv.brand:Xiaomi

Before the mark 

 

o.house = (House) house.clone();  

 Because of this line of code, house2 will shallowly copy all the common type variables in house1, and because tv is a reference type variable, and there is no copy of the reference type variable in the process of copying house1, so house1 and house2 both point to tv at the same address.

After the mark 

​person2.house.tv.size = 90;   //添加
person2.house.tv.brand = "Xiaomi"; //添加

At this point, it should be easy to understand that after the above changes, the tv attributes in house1 and house2 have been changed together. 

o.tv = (TV) TV.clone();  

If you add code like the above in the house class, the result will be different 

 Through the above three experiments, to summarize, if you want to achieve deep copy, you only need to recursively copy all objects with reference type variables until the two outermost objects have nothing to do. The reason for the deep and shallow copy is that only the corresponding heap address (beginning with Ox) is saved when the reference type variable is saved in the object, and the Object.clone() method can only achieve shallow copy

Guess you like

Origin blog.csdn.net/weixin_48968045/article/details/112298265