Java clone object clone () usage and Function
Content summary
If you want to modify an object and do not want to change the caller's object, make a local copy of the object. This is also the most common use of local replicas. If you decide to make a local copy, simply use the clone () method. Clone means "Clone", that is, making exactly the same copy. This method is defined in the basic class Object as the "protected" mode. However, in any category class that you want to clone, you must overwrite it to the "public" mode. For example, the standard library class Vector overwrites clone (), so it can call clone () for the Vector (),
When writing the clone () method, there is usually a line of code super. clone (); clone has default behavior, super. clone (); because the Members in the parent class must be copied first, and then the members of the parent class should be copied.
Java cloned object
If you want to modify an object and do not want to change the caller's object, make a local copy of the object. This is also the most common use of local replicas. If you decide to make a local copy, simply use the clone () method. Clone means "Clone", that is, making exactly the same copy. This method is defined in the basic class Object as the "protected" mode. However, in any category class that you want to clone, you must overwrite it to the "public" mode. For example, the standard library class Vector overwrites clone (), so it can call clone () for the Vector, as shown below:
import java.util.*;class Int { private int i; public Int(int ii) { i = ii; } public void increment() { i++; } public String toString() { return Integer.toString(i); }}public class Cloning { public static void main(String[] args) { Vector v = new Vector(); for(int i = 0; i < 10; i++ ) v.addElement(new Int(i)); System.out.println(v: + v); Vector v2 = (Vector)v.clone(); for(Enumeration e = v2.elements(); e.hasMoreElements(); ) ((Int)e.nextElement()).increment(); System.out.println(v: + v); }}
The clone () method generates an Object, and the latter must be immediately recreated to the correct type. This example shows that the clone () method of the Vector cannot automatically clone every object contained in the Vector. Due to alias problems, the old Vector and the cloned Vector both contain the same object. We usually call this case "simple replication" or "Shallow replication" because it only copies the "surface" part of an object. In addition to the "surface", the actual object also includes all objects pointed to by the handle, and all other objects pointed to by those objects, and so on. This is the origin of "object network" or "object network. If you can copy all the networks, it is called "full replication" or "Deep replication ".
In the output, we can see the results of the shallow replication. Note that the actions taken on v2 will also affect v:
v: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]v: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Generally, since the objects contained in the Vector cannot be "cloned" (note ②), it is best not to try to clone those objects.
Clone a class
Although the clone method is defined in the most basic objects of all classes, the clone method is not automatically performed in each class. This seems incredible, because the basic class methods are certainly usable in the classes Class. But Java does. If you want to use the clone method in a class, the only way is to add some code to ensure the normal cloning.
Tips for using protected
To avoid the clone capability of every class we create by default, the clone () method gets "retained" (set to protected) in the basic class Object ). The consequence is that for client programmers who simply use this class, they will not have this method by default. Secondly, we cannot use a handle pointing to the base class to call clone () (although this is especially useful in some cases, such as cloning a series of objects in a multipleth way ). During the compilation period, this is actually a way to notify us that objects cannot be cloned-and most classes in the Java library cannot be cloned. Therefore, if we execute the following code:
Integer x = new Integer (l );
X = x. clone ();
In the compilation phase, an annoying error message pops up, telling us that clone () is inaccessible-Because Integer does not overwrite it, and it is the default value for protected ).
However, if we are in a class derived from the Object (all classes are derived from the Object), we have the right to call the Object. clone (), because it is "protected", and we are in an inherited generator. The basic class clone () provides a useful function-it performs a true "bitwise" Copy of the struct class object, so it is equivalent to a standard clone action. However, we need to set our clone operation to public. Otherwise, the clone operation cannot be accessed. In short, two key issues to be aware of during cloning are: super. clone () is almost certainly called, and the clone is set to public.
Sometimes you want to overwrite clone () in a deeper category. Otherwise, you can directly use our clone () (which is now public ), and that is not necessarily what we want (however, because Object. clone () has made a copy of the actual object, so this situation may also be allowed ). The protected technique can only be used once: It inherits from a class that does not have the cloning capability for the first time, and wants to make a class "Clone-able ". The clone () method can be used in any scenario inherited from our class, because Java cannot narrow the access scope of the Method After derivation. In other words, once an object becomes cloned, everything derived from it can be cloned, unless it is "disabled" by a special mechanism (discussed later.
Implement the Cloneable Interface
To complete the cloning of an object, you need to implement the Cloneable interface. This interface is a little strange, because it is empty!
Interface Cloneable {}
The reason why we want to implement this empty interface is obviously not because we are going to form a Cloneable and call a method of it. Some people think that using interfaces here is a "spoofing" behavior, because the features it uses are other ideas, not the original meaning. The implementation of Cloneable interface acts as a tag and encapsulates it into the class type.
Two reasons contribute to the existence of the Cloneable interface. First, there may be an upstream styling handle pointing to a basic type, and it does not know whether it can really clone that object. In this case, you can use the instanceof keyword (introduced in chapter 11th) to check whether the handle is indeed connected to the same cloned object:
If (myHandle instanceof Cloneable )//...
The second reason is that we may not want to clone all object types. Therefore, Object. clone () verifies whether a class implements the Cloneable interface. If the answer is no, "Throw" A CloneNotSupportedException violation. Therefore, in general, we must use "implement Cloneable" as part of the support for cloning capabilities.
Java clone implementation
After understanding all the details behind the implementation of the clone () method, you can create a class that can be easily copied to provide a local copy:
import java.util.*;class MyObject implements Cloneable { int i; MyObject(int ii) { i = ii; } public Object clone() { Object o = null; try { o = super.clone(); } catch (CloneNotSupportedException e) { System.out.println(MyObject can't clone); } return o; } public String toString() { return Integer.toString(i); }}public class LocalCopy { static MyObject g(MyObject v) { v.i++; return v; } static MyObject f(MyObject v) { v.i++; return v; } public static void main(String[] args) { MyObject a = new MyObject(11); MyObject b = g(a); if(a == b) System.out.println(a == b); else System.out.println(a != b); System.out.println(a = + a); System.out.println(b = + b); MyObject c = new MyObject(47); MyObject d = f(c); if(c == d) System.out.println(c == d); else System.out.println(c != d); System.out.println(c = + c); System.out.println(d = + d); }}
In any case, clone () must be accessible, so it must be set to public (public ). Second, as the initial action of clone (), the basic class version of clone () should be called. The clone () called here is pre-defined within the Object. It can be called because it has the protected attribute, so it can be accessed in the derivative class.
Object. clone () will check the size of the original Object, and free up enough memory for the new Object to copy all binary bits from the original Object to the new Object. This is called "bitwise replication". In general, this job should be done by the clone () method. However, before Object. clone () is formally started, it first checks whether a class is Cloneable, that is, whether it has the cloning capability-in other words, whether it has implemented the Cloneable interface. If not, the Object. clone () throws a CloneNotSupportedException violation, indicating that we cannot clone it. Therefore, we 'd better use a try-catch Block. the clone () call code is enclosed (or encapsulated) to try to capture a violation that should never occur (because the Cloneable interface has been implemented here ).
In LocalCopy, the two methods g () and f () reveal the differences between the two parameter transfer methods. G () demonstrates passing by reference. It modifies an external object and returns a reference to that external object. F () is a clone of the independent variable, so it is separated and the original object remains independent. Then it continues to do what it wants. You can even return a handle pointing to the new object without any side effects on the original object. Note the following odd statements:
V = (MyObject) v. clone ();
It is used to create a local copy. To avoid confusion by such a statement, remember that this strange encoding form is fully allowed in Java, because everything with a name is actually a handle. Therefore, handle v is used to clone a copy to which it points, and finally returns a handle pointing to the basic type Object (because it is in the Object. clone () is defined in that way), and then it must be modeled as the correct type.
In main (), the difference between the two parameter passing methods is that they test a different method. The output result is as follows:
a == ba = 12b = 12c != dc = 47d =48
Keep in mind the fact that Java does not check the internal structure of the compared objects to verify that the values of the objects are the same. = And! = The operator simply compares the content of the handle. If the address in the handle is the same, the handle points to the same object, so they are considered to be "equivalent. Therefore, the operator actually detects "is the handle pointing to the same object due to the alias problem ?"
Java Object. clone ()
What actually happens when you call Object. clone? When we override clone () in our own class, what is the most critical for super. clone? The clone () method in the root class is responsible for establishing the correct storage capacity, and copying the binary from the original object to the storage space of the new object through "bit replication. That is to say, it is not just a reserved bucket or an object to be copied-you need to check the exact size of the object to be copied and then copy the object. Because all these work is performed in the internal code defined by the root class's clone () method (the root class does not know what to inherit from itself ), as you may have guessed, this process requires RTTI to determine the actual size of the object to be cloned. In this way, the clone () method can create a correct number of buckets and perform correct bitwise replication for that type.
No matter what we want to do, the first part of the clone process is usually to call super. clone (). By performing an accurate copy, this can create a good foundation for subsequent clone processes. Then, you can take other necessary operations to complete the final cloning.
To know exactly what other operations are, first of all, we must correctly understand what Object. clone () brings to us. In particular, will it automatically clone all the targets pointed by the handle? The following example can be used to complete the detection:
public class Snake implements Cloneable { private Snake next; private char c; Snake(int i, char x) { c = x; if(--i > 0) next = new Snake(i, (char)(x + 1)); } void increment() { c++; if(next != null) next.increment(); } public String toString() { String s = : + c; if(next != null) s += next.toString(); return s; } public Object clone() { Object o = null; try { o = super.clone(); } catch (CloneNotSupportedException e) {} return o; } public static void main(String[] args) { Snake s = new Snake(5, 'a'); System.out.println(s = + s); Snake s2 = (Snake)s.clone(); System.out.println(s2 = + s2); s.increment(); System.out.println( after s.increment, s2 = + s2); }}
A Snake consists of several segments. Each segment is of the Snake type. Therefore, this is a linked list of segments. All segments are created in a circular manner. Each completed segment will reduce the value of the first builder parameter until it is finally zero. To assign a unique tag to each segment, the value of the second parameter (a Char) increases progressively during each loop builder call.
The increment () method increments each tag cyclically so that we can see the changes. The toString method prints each tag cyclically. The output is as follows:
S =: a: B: c: d: e
S2 =: a: B: c: d: e
After s. increment, s2 =: a: c: d: e: f
This means that only the first segment is copied by Object. clone (), so this is a kind of "Shallow copy ". If you want to copy the entire snake-that is, to perform "Deep replication"-you must take additional operations in the overwritten clone.
Generally, super. clone () can be called from a cloned class to ensure that all basic class actions (including Object. clone () can be performed. A clone () is explicitly called for each handle in the object; otherwise, those handles will be converted into original object handles by alias. The builder calls are also roughly the same-first construct the basic class, and then the next derivative builder ...... And so on until the derivative builder is at the deepest level. The difference is that clone () is not a builder, so there is no way to achieve automatic cloning. In order to clone, you must make it clear.
Clone a compositing object
A problem occurs when trying to deeply copy and synthesize objects. It must be assumed that the clone () method in the member object can also perform deep replication on its own handle in sequence, and so on. This makes our operations complicated. To achieve normal deep replication, you must control the code in all classes, or at least fully grasp the classes involved in deep replication to ensure that their own deep replication can be performed correctly.
The following example summarizes what needs to be done for deep replication of a compositing object:
class DepthReading implements Cloneable { private double depth; public DepthReading(double depth) { this.depth = depth; } public Object clone() { Object o = null; try { o = super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return o; }}class TemperatureReading implements Cloneable { private long time; private double temperature; public TemperatureReading(double temperature) { time = System.currentTimeMillis(); this.temperature = temperature; } public Object clone() { Object o = null; try { o = super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return o; }}class OceanReading implements Cloneable { private DepthReading depth; private TemperatureReading temperature; public OceanReading(double tdata, double ddata){ temperature = new TemperatureReading(tdata); depth = new DepthReading(ddata); } public Object clone() { OceanReading o = null; try { o = (OceanReading)super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } o.depth = (DepthReading)o.depth.clone(); o.temperature = (TemperatureReading)o.temperature.clone(); return o; }}public class DeepCopy { public static void main(String[] args) { OceanReading reading = new OceanReading(33.9, 100.5); OceanReading r = (OceanReading)reading.clone(); }}
DepthReading and TemperatureReading are very similar; they both contain only basic data types. Therefore, the clone () method can be very simple: Call super. clone () and return the result. Note that the clone () code used by the two classes is completely consistent.
OceanReading is a combination of DepthReading and TemperatureReading objects. To perform deep replication, clone () must simultaneously clone the handles in OceanReading. To achieve this goal, the result of super. clone () must be shaped into an OceanReading object (to access the depth and temperature handles ).
Java. lang. Object contains a method clone ()
Protected Object clone ()
Throws CloneNotSupportedException is created and a copy of this object is returned. The exact meaning of a copy may depend on the class of the object. In this way, for any object x, the expression:
X. clone ()! = X is true, expression:
X. clone (). getClass () = x. getClass () is also true, but these are not required. Generally:
X. clone (). equals (x) is true, but this is not a requirement that must be met.
By convention, the returned object should be obtained by calling super. clone. If a class and all its superclasses (except objects) comply with this convention, x. clone (). getClass () = x. getClass ().
By convention, the object returned by this method should be independent of this object (the object being copied ). To obtain this independence, it is necessary to modify one or more fields of this object before super. clone returns an object. This usually means to copy all the variable objects that contain the internal "deep structure" of the replicated object, and replace the references to these objects with references to the copy. If a class only contains basic fields or references to unchanged objects, you do not need to modify the fields in the objects returned by super. clone.
Object Class clone method to perform specific replication operations. First, if the class of this object cannot implement the interface Cloneable, CloneNotSupportedException will be thrown. Note that all arrays are regarded as Cloneable interfaces. Otherwise, this method will create a new instance of the class of this object, and initialize all fields of this object using the content of the corresponding fields of this object just like by allocation; the content of these fields is not self-copied. Therefore, this method executes the "superficial copy" of the object, instead of "deep copy.
The Object class itself does not implement the interface Cloneable. Therefore, calling the clone method on an Object whose class is an Object will throw an exception during runtime.
Return Value:
A copy of the instance.
Throw:
CloneNotSupportedException-if the object class does not support the Cloneable interface, the subclass of the rewrite clone method will also throw this exception to indicate that an instance cannot be copied.
In fact, clone () is defined as protected for a reason, because sometimes some class instances do not want to be copied. How can we use this method? Only one super keyword is enough. The following example can explain the role and usage of clone:
public class C { static class Strings implements Cloneable { private String str; public void SetStr(String s){ this.str = s; } public String GetStr(){ return this.str; } public Object clone()throws CloneNotSupportedException{ return super.clone(); } } public static void main(String[] args) { try{ Strings str1 = new Strings(); str1.SetStr(Hello World!); System.out.println(-----------------); System.out.println(str1.SetStr(Hello World!);); System.out.println(str2 = (Strings)str1.clone();); Strings str2 = (Strings)str1.clone(); System.out.println(str1:+str1.GetStr()); System.out.println(str2:+str2.GetStr()); System.out.print(print object str1:); System.out.println(str1); System.out.print(print object str2:); System.out.println(str2); System.out.println(-----------------); System.out.println(str2.setStr(Hello!);); str2.SetStr(Hello!); System.out.println(str1:+str1.GetStr()); System.out.println(str2:+str2.GetStr()); System.out.print(print object str1:); System.out.println(str1); System.out.print(print object str2:); System.out.println(str2); System.out.println(-----------------); System.out.println(str1 = str2;); str1 = str2; System.out.print(print object str1:); System.out.println(str1); System.out.print(print object str2:); System.out.println(str2); System.out.println(-----------------); }catch(Exception ex){ System.out.println(ex.toString()); } }}
The running result is as follows:
-----------------str1.SetStr(Hello World!);str2 = (Strings)str1.clone();str1:Hello World!str2:Hello World!print object str1:C$Strings@de6cedprint object str2:C$Strings@c17164-----------------str2.setStr(Hello!);str1:Hello World!str2:Hello!print object str1:C$Strings@de6cedprint object str2:C$Strings@c17164-----------------str1 = str2;print object str1:C$Strings@c17164print object str2:C$Strings@c17164-----------------