Deep understanding of cloning _java in Java

Source: Internet
Author: User
Tags constructor serialization shallow copy static class

Objective

Java Cloning (clone) is one of the features of the Java language, but it is rarely used in practice. But sometimes cloning can be more convenient and more efficient.

For clones (clone), Java has some limitations:

1. The cloned class must implement the Cloneable interface itself to indicate that Object.clone() the method can legitimately replicate the class instance by field. The Cloneable interface is actually an identity interface and does not have any interface methods.

2. A class that implements the Cloneable interface should use a public method override Object.clone (it is protected). It is impossible for an object to clone it if it implements this interface. Even if the Clone method is a reflexive invocation, there is no guarantee that it will succeed.

3, in the Java.lang.Object class cloning method is so defined:

        Protected Object Clone ()
        throws Clonenotsupportedexception

Creates and returns a copy of this object. Indicates a protected method that is visible in the same package.

By convention, the returned object should be obtained by calling super.clone .

Assignments in Java

In Java, assignment is very common, and a simple assignment is as follows

Original type
int a = 1;
int b = A;

Reference type
string[] weekdays = new STRING[5];
string[] Gongzuori = weekdays;//Copy reference only

In the above code.

1, if the original data type, the assignment is passed the real value

2. If you are referencing a data type, the assignment is passed as a reference to the object, not an object.

Understanding the difference between data types and reference types makes it easy for us to understand clones.

Clone

In Java, clone is the process of copying an existing object in memory from another object that is identical to it. Clones in Java are domain-by-field replication.

To support the Clone method in Java, you need to implement the Cloneable interface first

Cloneable is actually a bit strange, it's different from the interface we use, it doesn't contain any methods, it's just a markup interface.

Its source code is as follows

Public interface Cloneable {
}

About cloneable, you need to be aware of

1, if you want to support clone, you need to implement the Cloneable interface

2. If there is no call clone method to implement the Cloneable interface, a Clonenotsupportedexception exception is thrown.

Then rewrite the Clone method and modify it to the public access level

Static Class Cloneableimp implements cloneable {public
 int count;
 public child child;
   
   
 @Override Public
 Object Clone () throws Clonenotsupportedexception {return
   super.clone ();
 }
}

Calling the Clone method to copy an object

Cloneableimp imp1 = new Cloneableimp ();
Imp1.child = new Child ("Andy");
try {
 Object obj = Imp1.clone ();
 Cloneableimp IMP2 = (cloneableimp) obj;
 System.out.println ("main imp2.child.name=" + imp2.child.name);
} catch (Clonenotsupportedexception e) {
 e.printstacktrace ();
}

Shallow copy

The above code implements a clone that actually belongs to a shallow copy (shallow copy).

About shallow copies, you should know.

1, using the default clone method

2. Make a value copy of the original data field

3. Copy references only for reference types

4, fast implementation, high efficiency

5, can not do 100% separation of data.

6. If an object contains only the original data field or the Mutable object field, it is recommended that you use a shallow copy.

With regard to the inability to do data separation, we can use this code to verify

Cloneableimp imp1 = new Cloneableimp ();
Imp1.child = new Child ("Andy");
try {
 Object obj = Imp1.clone ();
 Cloneableimp IMP2 = (cloneableimp) obj;
 Imp2.child.name = "Bob";
     
 System.out.println ("main imp1.child.name=" + imp1.child.name);
} catch (Clonenotsupportedexception e) {
 e.printstacktrace ();
}

The above code we use the Imp1 clone method to clone the IMP2, then modify it imp2.child.name to Bob, and then print imp1.child.name the result is

Main Imp1.child.name=bob

The reason is that a shallow copy does not do 100% separation of data, IMP1 and IMP2 share the same child object, so one modification affects the other.

Deep copy

Deep copy can solve the problem of data 100% separation. You just need to make some changes to the code above.

1, child implementation cloneable interface.

public class child implements cloneable{public

 String name;

 Public Child (String name) {
   this.name = name;
 }

 @Override public
 String toString () {return
   ' child [name= ' + name + '] ';
 }

 @Override
 protected Object Clone () throws Clonenotsupportedexception {return
   super.clone ();
 }
}

2. Rewrite the Clone method to invoke the Clone method of the data field.

Static Class Cloneableimp implements cloneable {public
 int count;
 public child child;
   
   
 @Override Public
 Object Clone () throws Clonenotsupportedexception {
   Cloneableimp obj = (cloneableimp) Super.clone ();
   Obj.child = (Child) Child.clone ();
   return obj;
 }
}

When we modify imp2.child.name it again it will not affect imp1.child.name the value because IMP1 and imp2 each have their own child objects because of the 100% isolation of the data.

Some features of deep copy

1, you need to rewrite the Clone method, not only the method of the parent class, but also call the attribute's Clone method

2, do the original object and clone object between 100% data separation

3, if the object has a reference type of properties, it is recommended to use a deep copy

4, deep copy is more time-consuming and less efficient than shallow copy

Why use clones

The important and common common is that an API needs to provide a list collection, but does not want the caller's modifications to affect its own changes, so it is necessary to clone an object to achieve the purpose of data isolation.

Should try to avoid clone

1. Typically, an interface is implemented to show what the class can do for its customers, and cloneable is just a markup interface, and it also changes the behavior of the method of hand protection in the superclass, an extremely atypical use of the interface and is not worth emulating.

The Javadoc description of the 2.Clone method convention and its fragile clone method is somewhat ambiguous, as follows for the Java SE8 Convention

The Clone method creates and returns a copy of the object. The exact meaning of the copy depends on the class of the object. The general implication is that for any object x, an expression

x.clone() != x 为 true x.clone().getClass() == x.getClass() also returns true, but does not have to x.clone().equals(x) return true, but is not required

The second and third expressions above can easily return false. So the only thing that can guarantee permanent true is the expression one, that is, two objects are independent objects.

3. The final domain of the Mutable object in the Clone method, if we need to copy the final domain of the Mutable object, it cannot actually be compiled because of the final limit. Therefore, in order to implement cloning, we need to consider the final keyword of the mutable object domain.

4. Thread safety If you decide to implement the Cloneable interface with a thread-safe class, you need to ensure that its Clone method is synchronized. The default Object.clone method is not to do synchronization.

In general, the Clone method in Java is not actually perfect, and it is recommended that you avoid it as much as possible. The following are some alternative scenarios.

Copy Constructors

You can also implement copies of objects by using the Copy Builder.

1, the copy constructor is also a constructor

2, accept only one parameter, the parameter type is the current class

3, the purpose is to generate a new object with the same parameters

4, copy the constructor compared to the advantages of the Clone method is simple, easy to implement.

A code example that uses the Copy Builder

public class Car {
 Wheel Wheel;
 String manufacturer;
 
 Public car (Wheel Wheel, String manufacturer) {
   this.wheel = Wheel;
   This.manufacturer = manufacturer;
 }
 
 Copy constructor public car (car car
 ) {This
   (Car.wheel, car.manufacturer);
 }
 
 public static class Wheel {
   String brand;
 }
}

Note that the above code is implemented as a shallow copy, and if you want to implement a deep copy, refer to the following code

Copy constructor public car (car car
) {
 Wheel Wheel = new Wheel ();
 Wheel.brand = Car.wheel.brand;
   
 This.wheel = wheel;
 This.manufacturer = Car.manufacturer;
}

In order to be more convenient, we can also add a static method for the above class

public static car newinstance [car] {return
 new car (car);
}

Using serializable to implement deep copy

In fact, using serialization can also implement deep copies of objects. The abbreviated code is as follows

public class Deepcopyexample implements serializable{
 private static final long Serialversionuid = 6098694917984051357L;
 public child child;
 
 Public deepcopyexample Copy () {
   deepcopyexample copy = null;
   try {
     Bytearrayoutputstream BAOs = new Bytearrayoutputstream ();
     ObjectOutputStream oos = new ObjectOutputStream (BAOs);
     Oos.writeobject (this);
 
     Bytearrayinputstream Bais = new Bytearrayinputstream (Baos.tobytearray ());
     ObjectInputStream ois = new ObjectInputStream (Bais);
     copy = (deepcopyexample) ois.readobject ();
   } catch (IOException e) {
     e.printstacktrace ();
   } catch (ClassNotFoundException e) {
     e.printstacktrace ();
   }
   return copy;
 }

Where the child must implement the Serializable interface

public class child implements serializable{
 private static final long serialversionuid = 6832122780722711261L;
 Public String name = "";

 Public Child (String name) {
   this.name = name;
 }

 @Override public
 String toString () {return
   ' child [name= ' + name + '] ';
 }
}

Working with examples and testing code

deepcopyexample example = new Deepcopyexample ();
Example.child = new Child ("example");
   
Deepcopyexample copy = Example.copy ();
if (copy!= null) {
 copy.child.name = "Copied";
 System.out.println ("example.child=" + Example.child + "; copy.child=" + Copy.child);
}
Output results: example.child=child [Name=example];copy.child=child [name=copied]

From the output, the change of the child value of the Copy object does not affect the child value of the example object, that is, a deep copy of the object can be implemented using serialization.

Summarize

The above is the entire content of the cloning in Java, I hope this article for you to learn Java can help.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.