Directory
Prerequisites
Why clone?
Object clone and why
How to clone
Clone attitude
Other options
Comparison with serializable
Performance
Prerequisites
To Understand Java clone, you must first review the following knowledge.
Java is classified into two categories: primitive, Int, and reference, such as string and object.
Java references are stored on the stack. Java code
public class B { int a; String b; public B(int a, String b) { super(); this.a = a; this.b = b; } }
Public Class B {
Int;
String B;
Public B (int A, string B ){
Super ();
This. A =;
This. B = B;
}
}
For such an instance of reference type, we can speculate that the memory storage form of the instance on the stack (excluding the reference pointing to the class, lock management, and so on, the internal office occupies the memory ), there should be an int value indicating a and a reference that points to the bucket on the heap of B.
Why clone?
Well, because of the need. Nonsense.
In the famous gof design pattern, there is a prototype pattern, specifying the object type to create with the prototype instance, and creating new objects by copying these prototype.
Simply put, clone an object instance. Make the cloned copy exactly the same as the original object.
Insert a simple clone example. If an object contains a mutable object instance, the public API should not directly return a reference to the object, in case the caller's code changes the internal status of the object. In this case, the object clone can be returned.
The question is, what is exactly the same.
Generally
X. Clone ()! = X
X. Clone (). getclass () = x. getclass ()
X. Clone (). Equals (X)
However, these are not mandatory.
We need to clone what we need.
In general, the clone we want should be like this. Copy is the same as the prototype, but is isolated from each other. That is, after cloning, changing one does not affect the other.
Object clone and why
Object clone is the simplest. In terms of memory storage on the heap (excluding internal memory), the clone of object A is to allocate a place on the heap that is as large as the storage space occupied by object A on the heap, then copy the memory content on the heap of A to the allocated memory space.
Let's look at the example. Java code
Class user {
String name;
Int age;
}
Class account implements cloneable {
User user;
Long balance;
@ Override
Public object clone () throws clonenotsupportedexceptiOn {
Return super. Clone ();
}
}
Java code
// User. user user = new user (); User. name = "user"; user. age = 20; // account. account account = new account (); account. user = user; account. balance = 10000; // copy. account copy = (account) account. clone (); // balance because it is primitive, copy and prototype are equal and independent. Assert. assertequals (copy. Balance, account. Balance); copy. Balance = 20000; // changing copy does not affect the prototype. Assert. asserttrue (copy. Balance! = Account. Balance); // because the user is of the reference type, the copy and prototype references are the same. Assert. asserttrue (copy. User = Account. User); copy. User. Name = "newname"; // The Same Thing is changed. Assert. assertequals ("newname", account. User. Name );
// User
User user = new user ();
User. Name = "user ";
User. Age = 20;
// Account.
Account account = new account ();
Account. User = user;
Account. Balance = 10000;
// Copy.
Account copy = (account) account. Clone ();
// Because balance is primitive, copy and prototype are equal and independent.
Assert. assertequals (copy. Balance, account. Balance );
Copy. Balance = 20000;
// Changing copy does not affect the prototype.
Assert. asserttrue (copy. Balance! = Account. Balance );
// Because the user is a reference type, the copy and prototype references the same.
Assert. asserttrue (copy. User = Account. User );
Copy. User. Name = "newname ";
// Change the same thing.
Assert. assertequals ("newname", account. User. Name );
Well, the default implementation is to help us, but not all.
Primitive does achieve equality and isolation.
The reference type only copies the reference. The copy and prototype references the same thing.
This is the so-called shortest copy.
Deep copy is required, that is, copying the memory copy of objects in the prototype, not just a reference. Only by yourself.
Wait. Do all the reference types require deep copy?
No!
The reason why we need deep copy is that the default Implementation of the provided light copy is not isolated, in other words, changing the copy will affect the internal prototype. For example, changing the name of the copy user affects the prototype.
If the class we want to copy is immutable, such as string, there is no way to change its internal state. Java code
class User implements Cloneable { String name; int age; @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } }
Class user implements cloneable {
String name;
Int age;
@ Override
Public object clone () throws clonenotsupportedexceptiOn {
Return super. Clone ();
}
}Java code
// User.
User user = new user ();
User. Name = "user ";
User. Age = 20;
// Copy
User copy = (User) user. Clone ();
// Because age is primitive, copy and prototype are equal and independent.
Assert. assertequals (copy. Age, user. Age );
Copy. Age = 30;
// Changing copy does not affect the prototype.
Assert. asserttrue (copy. Age! = User. Age );
// Because name is a reference type, copy and prototype reference are the same.
Assert. asserttrue (copy. Name = user. Name );
// String is an unchangeable class. There is no way to change this string through the copy. Name operation.
// Changing the referenced object does not affect the prototype.
Copy. Name = "newname ";
Assert. assertequals ("newname", copy. Name );
Assert. assertequals ("user", user. Name );
// User. user user = new user (); User. name = "user"; user. age = 20; // copy user copy = (User) user. clone (); // age because it is primitive, copy and prototype are equal and independent. Assert. assertequals (copy. Age, user. Age); copy. Age = 30; // changing copy does not affect the prototype. Assert. asserttrue (copy. Age! = User. Age); // name because it is a reference type, the copy and prototype references are the same. Assert. asserttrue (copy. Name = user. Name); // string is an unchangeable class. There is no way to change this string through the copy. Name operation. // Changing the referenced object does not affect the prototype. Copy. Name = "newname"; Assert. assertequals ("newname", copy. Name); Assert. assertequals ("user", user. Name );
It can be seen that when cloning, primitive and immutable object types can be treated similarly.
Why is clone implemented in Java?
You may have the following considerations.
1. Efficiency and Simplicity: simply copy the memory of an object on the heap is much more efficient and simple than traversing an object network and then copying the memory depth.
2. Do not impose meaning on other classes. If cloneable is implemented by a and a reference is directed to B, if the memory is directly copied for deep copy, B also supports clone, but this is done in a using B, and B does not even know. Destroys B's original interface.
3. the semantics may be damaged. If a implements cloneable and a reference points to B, B is implemented in singleton mode. If the memory is directly copied for deep copy, the singleton mode of B is destroyed.
4. It is convenient and more flexible. If a references an immutable object, memory deep copy is a waste. Shadow Copy gives programmers better flexibility.
How to clone
Clone trilogy.
1. Implement the cloneable interface.
2. Call super. clone to get an object. If there is no problem with the clone Implementation of the parent class, all fields defined by the parent class have been cloned in the memory storage of the object, the primitive and immutable type references in this class are also cloned, And the mutable type references are all shortest copies.
3. Point the reference of the shortest copy to the new clone of the prototype object.
Here is an example. Java code
Class user implements cloneable {
String name;
Int age;
@ Override
Public user clone () throws clonenotsupportedexceptiOn {
Return (User) Super. Clone ();
}
}
Class account implements cloneable {
User user;
Long balance;
@ Override