Introduction to java clone (deep copy/shallow copy)

Introduction to Cloning

During the development process, it may be necessary to copy some complex objects or when returning data to the caller, the caller will use clone to clone the data if the modification of the returned data will not affect the original data; implement the Cloneable interface and Rewrite the clone method; because of the problem of passing by value in java, cloning is divided into shallow clone and deep clone

Shallow clone

Shallow cloning will create an object in the heap memory, and assign all the attribute values ​​of the cloned object (including the value of the basic type and the reference value of the reference type) to the new object; modifying the attributes of the cloned basic type will not affect Corresponding properties of the cloned object. Modifying the properties of the cloned reference type will affect the properties of the corresponding cloned object;

package test;

public class CloneTest {
    
    
	public static class Outer implements Cloneable {
    
    
		private int outerInt;
		private String outerString;
		private Inner inner = null;

		public int getOuterInt() {
    
    
			return outerInt;
		}

		public void setOuterInt(int outerInt) {
    
    
			this.outerInt = outerInt;
		}

		public String getOuterString() {
    
    
			return outerString;
		}

		public void setOuterString(String outerString) {
    
    
			this.outerString = outerString;
		}

		public Inner getInner() {
    
    
			return inner;
		}

		public void setInner(Inner inner) {
    
    
			this.inner = inner;
		}

		@Override
		public String toString() {
    
    
			return "Outer [outerInt=" + outerInt + ", outerString=" + outerString + ", inner=" + inner + "]";
		}

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

	}

	public static class Inner {
    
    
		int innerInt;
		String innerString;

		public int getInnerInt() {
    
    
			return innerInt;
		}

		public void setInnerInt(int innerInt) {
    
    
			this.innerInt = innerInt;
		}

		public String getInnerString() {
    
    
			return innerString;
		}

		public void setInnerString(String innerString) {
    
    
			this.innerString = innerString;
		}

		@Override
		public String toString() {
    
    
			return "Inner [innerInt=" + innerInt + ", innerString=" + innerString + "]";
		}
	}

	public static void main(String[] args) throws CloneNotSupportedException {
    
    
		Inner inner = new Inner();
		inner.setInnerInt(10);
		inner.setInnerString("ceshi_inner");

		Outer outer = new Outer();
		outer.setOuterInt(11);
		outer.setOuterString("ceshi_outter");
		outer.setInner(inner);

		System.out.println("原始数据---");
		System.out.println("Outer: " + outer + " hashcode:" + outer.hashCode());
		System.out.println("Outer中inner--hashcode:" + outer.inner.hashCode());

		Outer clOuter = outer.clone();
		System.out.println("克隆后---");
		System.out.println("clOuter: " + clOuter + " hashcode:" + clOuter.hashCode());
		System.out.println("clOuter中inner--hashcode:" + clOuter.inner.hashCode());

		clOuter.setOuterInt(12);
		clOuter.setOuterString("ceshi_clOuter");
		clOuter.inner.setInnerInt(13);
		clOuter.inner.setInnerString("ceshi_clInner");

		System.out.println("克隆后修改数据,然后对比克隆后的对象和克隆前的对象---");
		System.out.println("---------------------------被克隆对象---------------------------");
		System.out.println("Outer: " + outer + " hashcode:" + outer.hashCode());
		System.out.println("Outer中inner--hashcode:" + outer.inner.hashCode());
		System.out.println("---------------------------克隆的对象---------------------------");
		System.out.println("clOuter: " + clOuter + " hashcode:" + clOuter.hashCode());
		System.out.println("clOuter中inner--hashcode:" + clOuter.inner.hashCode());

	}

}

operation result

Insert picture description here
Drawing analysis
First, there is an inner and outer objects on the stack, which respectively point to an address in the heap memory, which are used 0x****1and 0x*****2distinguished here ; after cloning, a clOuter object reference will be created in the stack, and a new memory address 0x****3will be opened in the heap memory, and the object will be cloned. The attribute values ​​of the outterint and outterString are copied and assigned. Because the value of the reference type is stored in the address (0x 1), the copied object will point to 0x 1 as the cloned object ; therefore, modify the attribute of the object of the reference type of the cloned object , Which is equivalent to the same inner object of the operation, so it will affect the value of the object's reference type attribute of the copied object
Insert picture description here

Deep clone

Deep cloning is to clone the attribute value of the reference type (the Inner object in the code) on the basis of the shallow clone, so that the attribute value of the cloned reference type and the attribute value of the cloned reference type point to the heap memory Different addresses; thus modifying the attribute value of the reference type after cloning will not affect the corresponding attribute value of the cloned object;

The code is to make the reference type object also implement the Cloneable interface and rewrite the clone method, and add a clone of the object's internal reference type attribute object to the clone method of the cloned object; intuitive understanding is that when the object is cloned, it is also Clone its internal reference type attribute object

package test;

public class CloneTest {
    
    
	public static class Outer implements Cloneable {
    
    
		private int outerInt;
		private String outerString;
		private Inner inner = null;

		public int getOuterInt() {
    
    
			return outerInt;
		}

		public void setOuterInt(int outerInt) {
    
    
			this.outerInt = outerInt;
		}

		public String getOuterString() {
    
    
			return outerString;
		}

		public void setOuterString(String outerString) {
    
    
			this.outerString = outerString;
		}

		public Inner getInner() {
    
    
			return inner;
		}

		public void setInner(Inner inner) {
    
    
			this.inner = inner;
		}

		@Override
		public String toString() {
    
    
			return "Outer [outerInt=" + outerInt + ", outerString=" + outerString + ", inner=" + inner + "]";
		}

		@Override
		protected Outer clone() throws CloneNotSupportedException {
    
    
			Outer outer = (Outer) super.clone();
			outer.inner = outer.inner.clone();
			return outer;
		}

	}

	public static class Inner implements Cloneable {
    
    
		int innerInt;
		String innerString;

		public int getInnerInt() {
    
    
			return innerInt;
		}

		public void setInnerInt(int innerInt) {
    
    
			this.innerInt = innerInt;
		}

		public String getInnerString() {
    
    
			return innerString;
		}

		public void setInnerString(String innerString) {
    
    
			this.innerString = innerString;
		}

		@Override
		public String toString() {
    
    
			return "Inner [innerInt=" + innerInt + ", innerString=" + innerString + "]";
		}

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

	}

	public static void main(String[] args) throws CloneNotSupportedException {
    
    
		Inner inner = new Inner();
		inner.setInnerInt(10);
		inner.setInnerString("ceshi_inner");

		Outer outer = new Outer();
		outer.setOuterInt(11);
		outer.setOuterString("ceshi_outter");
		outer.setInner(inner);

		System.out.println("原始数据---");
		System.out.println("Outer: " + outer + " hashcode:" + outer.hashCode());
		System.out.println("Outer中inner--hashcode:" + outer.inner.hashCode());

		Outer clOuter = outer.clone();
		System.out.println("克隆后---");
		System.out.println("clOuter: " + clOuter + " hashcode:" + clOuter.hashCode());
		System.out.println("clOuter中inner--hashcode:" + clOuter.inner.hashCode());

		clOuter.setOuterInt(12);
		clOuter.setOuterString("ceshi_clOuter");
		clOuter.inner.setInnerInt(13);
		clOuter.inner.setInnerString("ceshi_clInner");

		System.out.println("克隆后修改数据,然后对比克隆后的对象和克隆前的对象---");
		System.out.println("---------------------------被克隆对象---------------------------");
		System.out.println("Outer: " + outer + " hashcode:" + outer.hashCode());
		System.out.println("Outer中inner--hashcode:" + outer.inner.hashCode());
		System.out.println("---------------------------克隆的对象---------------------------");
		System.out.println("clOuter: " + clOuter + " hashcode:" + clOuter.hashCode());
		System.out.println("clOuter中inner--hashcode:" + clOuter.inner.hashCode());

	}

}


Insert picture description here
Drawing analysis of running results
On the basis of shallow cloning, the object of the reference type attribute of the cloned object is cloned again, so that the reference type attribute value of the cloned object and the cloned object point to different addresses in the heap memory (0x 1, 0x 3), so that modifying the value of the reference type attribute object of the cloned object (0x****3) will not affect the value of the reference type attribute object of the cloned object
Insert picture description here

Reference:
The role of the Cloneable interface and an in-depth understanding of deep clone and shallow clone
Java clone() and new efficiency comparison

Guess you like

Origin blog.csdn.net/nongminkouhao/article/details/108497982