Java-like clone (copy)

Let's say you want to copy a simple variable. It is simple:

Apples. 5 = int;
int = Pears Apples;
just int type, seven other primitive data types (boolean, char, byte, short , float, double.long) is equally applicable to such cases.

But if you are copying an object, the situation is somewhat complicated.

Let's say I'm a beginner, I would write:

class Student {
private int number;

public int getNumber() {
return number;
}

public void setNumber(int number) {
this.number = number;
}

}
public class Test {

public static void main(String args[]) {
Student stu1 = new Student();
stu1.setNumber(12345);
Student stu2 = stu1;

   System.out.println("学生1:" + stu1.getNumber());  
   System.out.println("学生2:" + stu2.getNumber());  

}
}
Result:
Student 1: 12345
Student 2: 12345
Here we defined a student from class, there is only one number field.

We created a new student instance, and then assign that value to stu2 instance. (Student stu2 = stu1;)

Look at the print results, as a novice, patted the chest and abdomen, but the object replication so!

Is it really the case?

We try to change stu2 instance number field, and then print the results to see:

stu2.setNumber (54321);
System.out.println ( "Student. 1:" + stu1.getNumber ());
System.out.println ( "Student 2:" + stu2.getNumber ()) ;
Results:

Student 1: 54321
Student 2: 54321

This is strange, why change the student number 2, student number 1 has also undergone a change?

The reason for the (stu2 = stu1) this one. The statement is the role of reference assigned to stu2 stu1 so, stu1 and stu2 point to the same object on the heap. Figure:

So, how to achieve a target copy of it?

If you remember the king of Object million class. There are 11 methods, there are two methods of protected, which is a clone method.

In Java, all classes are inherited from the default class Object Java language package, view its source code, you can copy src.zip under your JDK directory to somewhere else and then extract, which is all of Source. We found that there are a qualifier for the protected access method clone of ():

/*
Creates and returns a copy of this object. The precise meaning of “copy” may depend on the class of the object.
The general intent is that, for any object x, the expression:

  1. x.clone() != x will be true
  2. x.clone().getClass() == x.getClass() will be true, but these are not absolute requirements.
  3. . x.clone () the equals (the X-) by Will BE to true, not the this IS AN Absolute Requirement.
    * /
    protected native Object clone () throws CloneNotSupportedException;
    a closer look, it is a native method, we all know that native method is non-Java language code implementation, the program calls for Java, because Java programs are run in a virtual machine JVM above to gain access to the more there is no way associated with the underlying operating system, and can only be achieved by a language close to the operating system.

The first statement to ensure that the clone will have a separate memory address allocation.

The second statement indicates that the original clone and should have the same object class type, but it is not mandatory.

The third statement indicates that the original and cloned object should be equal equals () method, but it is not mandatory.

Because each type of direct or indirect parent classes are Object, they contain clone () method, but since the process is protected, it can not be accessed outside the class.

To copy on an object, we need to override the method to clone.

Why clone?

First think about a question, why the need to clone objects? Direct a new object is not it?

The answer is: clone objects may contain some of which have modified properties, and properties new out of the object are still initializes the value of time, so when you need a new object to hold the current object "state" to rely on clone method has. So I put the properties of this object a temporary assignment to give me a new new thing will do no object? Can be, but the one trouble is not that, and secondly, we have found through the above source of clone is a native way, it is how fast, in the underlying implementation.

Mind you, we have a common Object a = new Object (); Object b; b = a; copy of this form of the code is a reference to that object's address in memory, a and b objects still point to the same object .

The object is assigned by the clone method with an object at the same time when the original independent existence.

How to achieve cloning

First introduce two different methods of cloning, shallow clone (ShallowClone) and deep clone (DeepClone).

In the Java language, into the data type value type (basic data types) and reference types, including value type int, double, byte, boolean, char and other simple data types, including complex type reference type class, an interface, an array like. The main difference between deep and shallow clone clone that supports copy member variables of a reference type, the following will both be described in detail.

General step (shallow clone):

  1. Copied need to achieve Clonenable interface (not implemented if the call clone CloneNotSupportedException method throws exception), the interface is a marker interface (excluding any method)

  2. Covering the clone () method, set the access modifier public. Method call super.clone () method to get copied object you want. (Native local method)

Next, the above method to transform:

class Student implements Cloneable{
private int number;

public int getNumber() {
return number;
}

public void setNumber(int number) {
this.number = number;
}

@Override
public Object clone() {
Student stu = null;
try{
stu = (Student)super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return stu;
}
}
public class Test {
public static void main(String args[]) {
Student stu1 = new Student();
stu1.setNumber(12345);
Student stu2 = (Student)stu1.clone();

   System.out.println("学生1:" + stu1.getNumber());  
   System.out.println("学生2:" + stu2.getNumber());  
     
   stu2.setNumber(54321);  
 
   System.out.println("学生1:" + stu1.getNumber());  
   System.out.println("学生2:" + stu2.getNumber());  

}
}
Result:

Student 1: 12345
Student 2: 12345
Student 1: 12345
Student 2: 54321

If you do not believe these two objects are not the same object, then you can look at this sentence:

System.out.println(stu1 == stu2); // false

The above is referred to as a shallow copy clone.

There is also a slightly more complex deep copy:

We add an Address class in the student class.

class Address {
private String add;

public String getAdd() {
return add;
}

public void setAdd(String add) {
this.add = add;
}

}

class Student implements Cloneable{
private int number;

private Address addr;

public Address getAddr() {
return addr;
}

public void setAddr(Address addr) {
this.addr = addr;
}

public int getNumber() {
return number;
}

public void setNumber(int number) {
this.number = number;
}

@Override
public Object clone() {
Student stu = null;
try{
stu = (Student)super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return stu;
}
}
public class Test {

public static void main(String args[]) {

   Address addr = new Address();  
   addr.setAdd("杭州市");  
   Student stu1 = new Student();  
   stu1.setNumber(123);  
   stu1.setAddr(addr);  
     
   Student stu2 = (Student)stu1.clone();  
     
   System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());  
   System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());  

}
}
Result:

Student 1: 123, Address: Hangzhou
Student 2: 123, Address: Hangzhou

At first glance no problem, is it really?

We try to change the address addr instance in the main method.

addr.setAdd ( "Lake District");
System.out.println ( "Student 1:" + stu1.getNumber () + ", Address:." + stu1.getAddr () getAdd ());
System.out.println ( "student 2:" + stu2.getNumber () + ", address:". + stu2.getAddr () getAdd ());
results:

Student 1: 123, Address: Hangzhou
Student 2: 123, Address: Hangzhou
Student 1: 123, Address: West Lake District
Student 2: 123 Address: West Lake District

This is strange, how two students address has changed?

The reason is shallow copy just copy the reference variable addr, does not really open up another piece of space, the value is copied and then returned to the new object references.

Therefore, in order to achieve a true copy an object, rather than purely a reference copy. We need to replicate class of Address, and modifying the clone method, complete code is as follows:

package abc;

class Address implements Cloneable {
private String add;

public String getAdd() {
return add;
}

public void setAdd(String add) {
this.add = add;
}

@Override
public Object clone() {
Address addr = null;
try{
addr = (Address)super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return addr;
}
}

class Student implements Cloneable{
private int number;

private Address addr;

public Address getAddr() {
return addr;
}

public void setAddr(Address addr) {
this.addr = addr;
}

public int getNumber() {
return number;
}

public void setNumber(int number) {
this.number = number;
}

@Override
public Object clone() {
Student stu = null;
try{
stu = (Student)super.clone(); //浅复制
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
stu.addr = (Address)addr.clone(); //深度复制
return stu;
}
}
public class Test {

public static void main(String args[]) {

   Address addr = new Address();  
   addr.setAdd("杭州市");  
   Student stu1 = new Student();  
   stu1.setNumber(123);  
   stu1.setAddr(addr);  
     
   Student stu2 = (Student)stu1.clone();  
     
   System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());  
   System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());  
     
   addr.setAdd("西湖区");  
     
   System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());  
   System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());  

}
}
Result:

Student 1: 123, Address: Hangzhou
Student 2: 123, Address: Hangzhou
Student 1: 123, Address: West Lake District
Student 2: 123, Address: Hangzhou

This result is consistent with our ideas.

Finally, we can look at API in which a class that implements the clone method:

java.util.Date:

/**

  • A Copy Object of the this the Return.
    * /
    Public Object clone () {
    a Date D = null;
    the try {
    D = (a Date) to super.clone ();
    IF (! CDate = null) {
    d.cdate = (BaseCalendar.Date) cdate.clone ();
    }
    } the catch (CloneNotSupportedException E) {} // Will Not happen
    return D;
    }
    class actually belong to a deep copy.

Shallow clone and a deep clone

1, a shallow clone

In shallow clones, if the member variable prototype object is a value type, the copy to clone; member variables If the prototype object is a reference type, the address of the referenced object to clone a copy of the object that is the prototype member variable object and clone the object point to the same memory address.

Briefly, in the shallow clones, only when an object is copied copy the value type itself and member variables contained therein, and the object reference type member and is not copied.

In the Java language, may be achieved by covering a shallow clone clone Object class () method.

2, a deep clone

In deep clone, the member variables regardless prototype object is a value type or reference type, would be to clone a copy of the object, all references to objects deep clone will also copy the prototype object to clone.

Briefly, deep clones, in addition to copying the object itself, all member variables contained objects will be copied.

In the Java language, if necessary to achieve a deep clone may be covered by clone Object class () method, it may also be implemented by a sequence of (the Serialization) or the like.

(If the reference type which also contains many references to the type, or class of which the inner reference type contains a reference to another type, the method using the clone will be very troublesome. In this case we can use the sequence of the ways to achieve a deep clone objects.)

Serialization is the process flow of objects written, to the stream object is a copy of the original object, and the original object still exists in memory. Serialization achieved by copying only the object itself can be copied, and its member object references can be copied, so written by a sequence of object streams, and from which the stream read out a deep clone may be achieved. Note that to achieve its serialized object class must implement the Serializable interface, or can not achieve serialization operation.

To solve the multi-layered cloning

If the reference type which also contains many references to the type, or class of which the inner reference type contains a reference to another type, the method using the clone will be very cumbersome. Then we can use the serialization approach to achieve deep cloning objects.

Outer class the implements the Serializable {public
Private Long static Final serialVersionUID = 369285298572941L; // preferably explicitly declared ID
public Inner Inner;
 // Discription: [deep copy method, a subject in need, and all objects are achieved serialized object properties] 
public myclone Outer () {
Outer Outer = null;
the try {// stream into the target sequence, as written in the stream is a copy of the object, the original object still exists inside the JVM. Therefore, this feature may be implemented using a deep copy object
ByteArrayOutputStream new new ByteArrayOutputStream BAOS = ();
the ObjectOutputStream the ObjectOutputStream OOS new new = (BAOS);
oos.writeObject (the this);
      // into the stream sequence subject
ByteArrayInputStream bais = new ByteArrayInputStream (baos.toByteArray ());
the ObjectInputStream new new OIS = the ObjectInputStream (Bais);
Outer = (Outer) ois.readObject ();
} the catch (IOException E) {
e.printStackTrace ();
} the catch (a ClassNotFoundException E) {
e.printStackTrace ();
}
return Outer;
}
}
Inner must also implement Serializable, otherwise it can not be serialized:

Inner class the implements the Serializable {public
Private Long serialVersionUID = Final static 872390113109L; // preferably explicitly declared ID
public String name = "";

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

@Override
public String toString () {
return "Inner is the name:" + name;
}
}

This also enables the presence of two completely independent objects within the memory space, independently of each other's values.

to sum up

There are two ways to achieve the object cloning:

1) to achieve Cloneable interface and override clone () method of class Object;

2). Serializable interface implemented by an object sequence and deserialization

Realization of cloning, cloning can achieve real depth.

Code Serializable Cloneable interface and interfaces Java language provides a very simple, they are empty interface, this interface is also known as an empty marker interface that identifies the interface does not define any method of, its role is to tell the JRE implementation class whether these interfaces having a function, such as whether to support the cloning, the sequence of the other support.

Note: Based on cloning serialization and de-serialization to achieve not only the depth of cloning, more importantly, is limited by generics, you can check out if you want to clone objects support serialization, this check is complete compiler, not in Throws abnormal operation, this scheme is much better than the method using the clone clone Object class. Let problems at compile time exposed always better to leave the matter to the runtime.

reference

  • https://www.cnblogs.com/Qian123/p/5710533.html
Published 366 original articles · won praise 397 · views 270 000 +

Guess you like

Origin blog.csdn.net/qq_33589510/article/details/104798852