Home > Java > javaTutorial > Example tutorial of object cloning (Clone) in Java

Example tutorial of object cloning (Clone) in Java

零下一度
Release: 2017-07-19 10:00:01
Original
1584 people have browsed it

Part II<br>

When talking about object cloning, we have to talk about why objects should be cloned. All objects in Java are stored in the heap, and the heap is shared globally. In other words, if different methods of the same Java program can get a reference to an object, the referrer can modify the internal data of the object at will (provided that the internal data of the object is exposed through the get/set method) . Sometimes, the code we write wants the caller to get only one copy of the object (that is, an object with exactly the same content, but there are two such objects in the memory). Is there any way to do this? Of course it's a clone.

Part III

First of all, we are programmers, and of course we communicate in the language of our programmers.

import java.util.Date;
Copy after login
Copy after login
Copy after login
Copy after login
public class User implements Cloneable {
Copy after login
	private String username;
Copy after login
	private String password;
Copy after login
	private Date birthdate;
Copy after login
	public User(String username, String password, Date birthdate) {
Copy after login
		this.username = username;
Copy after login
		this.password = password;
Copy after login
		this.birthdate = birthdate;
Copy after login
	}
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
	@Override
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
	protected Object clone() throws CloneNotSupportedException {
Copy after login
Copy after login
		return super.clone();
Copy after login
Copy after login
	}
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
	@Override
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
	public int hashCode() {
Copy after login
Copy after login
		// 省略equals的实现(可用eclipse自动生成)
Copy after login
Copy after login
	}
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
	@Override
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
	public boolean equals(Object obj) {
Copy after login
Copy after login
		// 省略equals的实现(可用eclipse自动生成)
Copy after login
Copy after login
	}
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login

The above code builds a User class and implements the java.lang.Cloneable interface. As the name suggests, Cloneable means that this class can be cloned.

Let’s first take a look at what the java.lang.Cloneable interface has.

	// 省略一大堆get/set方法
Copy after login
}
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
/*
Copy after login
Copy after login
 * @(#)Cloneable.java	1.17 05/11/17
Copy after login
 *
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
Copy after login
Copy after login
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
Copy after login
Copy after login
 */
Copy after login
Copy after login
Copy after login
Copy after login
package java.lang;
Copy after login
Copy after login
/**
Copy after login
Copy after login
 * A class implements the Cloneable interface to
Copy after login
 * indicate to the {@link java.lang.Object#clone()} method that it
Copy after login
 * is legal for that method to make a
Copy after login

 * field-for-field copy of instances of that class.
Copy after login
 *
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
 * Invoking Object's clone method on an instance that does not implement the
Copy after login
 * Cloneable interface results in the exception
Copy after login

 * CloneNotSupportedException being thrown.
Copy after login
 *
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
 * By convention, classes that implement this interface should override
Copy after login
 * Object.clone (which is protected) with a public method.
Copy after login
 * See {@link java.lang.Object#clone()} for details on overriding this
Copy after login

 * method.
Copy after login
 *
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
 * Note that this interface does not contain the clone method.
Copy after login
 * Therefore, it is not possible to clone an object merely by virtue of the
Copy after login
 * fact that it implements this interface.  Even if the clone method is invoked
Copy after login
 * reflectively, there is no guarantee that it will succeed.
Copy after login
 *
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
 * @author  unascribed
Copy after login
Copy after login
 * @version 1.17, 11/17/05
Copy after login
 * @see     java.lang.CloneNotSupportedException
Copy after login
 * @see     java.lang.Object#clone()
Copy after login
 * @since   JDK1.0
Copy after login
Copy after login

Don’t be surprised, yes, except for a lot of chicken intestines, this interface does not define any methods sign. In other words, we want to clone an object, but it doesn't provide me with a method. So what to do? Don't be afraid, we still have the almighty Object class. Don't forget that he is the ancestor of all classes (a god-like existence), so you should go and greet him whenever you have nothing to do.

 */
Copy after login
Copy after login
Copy after login
Copy after login
public interface Cloneable {
Copy after login
}
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
/*
Copy after login
Copy after login
 * @(#)Object.java	1.73 06/03/30
Copy after login
 *
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
Copy after login
Copy after login
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
Copy after login
Copy after login
 */
Copy after login
Copy after login
Copy after login
Copy after login
package java.lang;
Copy after login
Copy after login
/**
Copy after login
Copy after login
 * Class Object is the root of the class hierarchy.
Copy after login
 * Every class has Object as a superclass. All objects,
Copy after login
 * including arrays, implement the methods of this class.
Copy after login
 *
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
 * @author  unascribed
Copy after login
Copy after login
 * @version 1.73, 03/30/06
Copy after login
 * @see     java.lang.Class
Copy after login
 * @since   JDK1.0
Copy after login
Copy after login
 */
Copy after login
Copy after login
Copy after login
Copy after login
public class Object {
Copy after login
    <br>
Copy after login
   // 省略N多的代码
Copy after login
    /**
Copy after login
     * Creates and returns a copy of this object.  The precise meaning
Copy after login
     * of "copy" may depend on the class of the object. The general
Copy after login
     * intent is that, for any object x, the expression:
Copy after login
     *
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
*
Copy after login
Copy after login
Copy after login
     * x.clone() != x
Copy after login
     * will be true, and that the expression:
Copy after login
     *
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
*
Copy after login
Copy after login
Copy after login
rrree

     * x.clone().getClass() == x.getClass()
Copy after login
     * will be true, but these are not absolute requirements.
Copy after login
     * While it is typically the case that:
Copy after login
     *
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
*
Copy after login
Copy after login
Copy after login

     * x.clone().equals(x)
Copy after login
     * will be true, this is not an absolute requirement.
Copy after login
     *
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
     * By convention, the returned object should be obtained by calling
Copy after login
     * super.clone.  If a class and all of its superclasses (except
Copy after login
     * Object) obey this convention, it will be the case that
Copy after login
     * x.clone().getClass() == x.getClass().
Copy after login
     *
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
     * By convention, the object returned by this method should be independent
Copy after login
     * of this object (which is being cloned).  To achieve this independence,
Copy after login
     * it may be necessary to modify one or more fields of the object returned
Copy after login

     * by super.clone before returning it.  Typically, this means
Copy after login
     * copying any mutable objects that comprise the internal "deep structure"
Copy after login
     * of the object being cloned and replacing the references to these
Copy after login
     * objects with references to the copies.  If a class contains only
Copy after login
     * primitive fields or references to immutable objects, then it is usually
Copy after login
     * the case that no fields in the object returned by super.clone
Copy after login
     * need to be modified.
Copy after login
     *
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
     * The method clone for class Object performs a
Copy after login
     * specific cloning operation. First, if the class of this object does
Copy after login
     * not implement the interface Cloneable, then a
Copy after login

     * CloneNotSupportedException is thrown. Note that all arrays
Copy after login
     * are considered to implement the interface Cloneable.
Copy after login
     * Otherwise, this method creates a new instance of the class of this
Copy after login
     * object and initializes all its fields with exactly the contents of
Copy after login
     * the corresponding fields of this object, as if by assignment; the
Copy after login
     * contents of the fields are not themselves cloned. Thus, this method
Copy after login
     * performs a "shallow copy" of this object, not a "deep copy" operation.
Copy after login
     *
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
     * The class Object does not itself implement the interface
Copy after login
     * Cloneable, so calling the clone method on an object
Copy after login
     * whose class is Object will result in throwing an
Copy after login
     * exception at run time.
Copy after login
     *
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
     * @return     a clone of this instance.
Copy after login

Haha, another big bunch of chicken intestines, don’t think I’m here To make up for the word count, these are technical articles written by Sun Java developers. Read more and talk less.

Yes, it is a native method. It is indeed a profound thing, but we still have to take advantage of it. Moreover, his method is protected, and he is clearly asking us to take advantage.

Continue to look at the test code below.

     * @exception  CloneNotSupportedException  if the object's class does not
Copy after login
     *               support the Cloneable interface. Subclasses
Copy after login
     *               that override the clone method can also
Copy after login
     *               throw this exception to indicate that an instance cannot
Copy after login
     *               be cloned.
Copy after login
     * @see java.lang.Cloneable
Copy after login
     */
Copy after login
    protected native Object clone() throws CloneNotSupportedException;
Copy after login
}
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
import java.util.Date;
Copy after login
Copy after login
Copy after login
Copy after login
import org.junit.Test;
Copy after login
Copy after login
Copy after login
public class TestCase {
Copy after login
Copy after login
Copy after login
<br>
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
	@Test
Copy after login
Copy after login
Copy after login
	public void testUserClone() throws CloneNotSupportedException {
Copy after login
		User u1 = new User("Kent", "123456", new Date());
Copy after login

This clone() method is really awesome. It clones our object in one go. The execution results are also in line with our expectations. The addresses of u1 and u3 are different but the content is the same.

Part IV

Through the above example, we can see that there are actually two steps to clone an object:

1. Let this class implement the java.lang.Cloneable interface;

2. Override (override) the clone() method of the Object class.

But, is it really that simple? Look at the code below again.

		User u2 = u1;
Copy after login
		User u3 = (User) u1.clone();
Copy after login
<br>
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
		System.out.println(u1 == u2);		// true
Copy after login
		System.out.println(u1.equals(u2));	// true
Copy after login
<br>
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
		System.out.println(u1 == u3);		// false
Copy after login
		System.out.println(u1.equals(u3));	// true
Copy after login
	}
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
<br>
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
}
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
public class Administrator implements Cloneable {
Copy after login
	private User user;
Copy after login
	private Boolean editable;
Copy after login
	public Administrator(User user, Boolean editable) {
Copy after login
		this.user = user;
Copy after login
		this.editable = editable;
Copy after login
	}
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
<br>
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
	@Override
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login

The above defines an Administrator class, which holds an object of the User class. Next, let's take a look at the effect of cloning the Administrator object.

	protected Object clone() throws CloneNotSupportedException {
Copy after login
Copy after login
		return super.clone();
Copy after login
Copy after login
	}
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
	@Override
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
	public int hashCode() {
Copy after login
Copy after login
		// 老规矩
Copy after login
Copy after login
	}
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
	@Override
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
	public boolean equals(Object obj) {
Copy after login
Copy after login
		// 老规矩
Copy after login
Copy after login
	}
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
	// 老规矩
Copy after login
}
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
import java.util.Date;
Copy after login
Copy after login
Copy after login
Copy after login
import org.junit.Test;
Copy after login
Copy after login
Copy after login
public class TestCase {
Copy after login
Copy after login
Copy after login
	@Test
Copy after login
Copy after login
Copy after login
	public void testAdministratorClone() throws CloneNotSupportedException {
Copy after login

Hehehe! Something went wrong. Java is so easy to master!

Here we can introduce two professional terms: shallow clone and deep clone.

The so-called shallow cloning, as the name suggests, is a very superficial clone. If we want to clone the Administrator object, we only clone itself and the reference addresses of all the objects it contains.

And deep cloning is not shallow cloning. Clone all objects except itself, including all object instances contained in itself. As for the level of deep cloning, it is determined by specific needs. There is also a saying of "N-level cloning".

However, all primitive type data, whether shallow clone or deep clone, will be cloned from the original value. After all, they are not objects and are not stored in the heap. Note: Basic data types do not include their corresponding wrapper classes.

If we want the object to be deeply cloned, we can modify the Administrator class like this.

		Administrator a1 = new Administrator(new User("Kent", "123456", new Date()), true);
Copy after login
		Administrator a2 = a1;
Copy after login
		Administrator a3 = (Administrator) a1.clone();
Copy after login
<br>
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
		System.out.println(a1 == a2);			// true
Copy after login
		System.out.println(a1.equals(a2));		// true
Copy after login

Since Boolean will cache the value, we do not need to clone the Boolean object. And the Boolean class does not implement the java.lang.Cloneable interface.

Part V

1. 让该类实现java.lang.Cloneable接口;

2. 确认持有的对象是否实现java.lang.Cloneable接口并提供clone()方法;

3. 重写(override)Object类的clone()方法,并且在方法内部调用持有对象的clone()方法;

4. ……

5. 多麻烦啊,调来调去的,如果有N多个持有的对象,那就要写N多的方法,突然改变了类的结构,还要重新修改clone()方法。

难道就没有更好的办法吗?

Part VI

接下来要重点介绍一下使用java.lang.Serializable来实现对象的深度克隆。

首先,我们编写一个工具类并提供cloneTo()方法。

import java.io.ByteArrayInputStream;
Copy after login
import java.io.ByteArrayOutputStream;
Copy after login
import java.io.IOException;
Copy after login
import java.io.ObjectInputStream;
Copy after login
import java.io.ObjectOutputStream;
Copy after login
public abstract class BeanUtil {
Copy after login
	@SuppressWarnings("unchecked")
Copy after login
	public static  T cloneTo(T src) throws RuntimeException {
Copy after login
		ByteArrayOutputStream memoryBuffer = new ByteArrayOutputStream();
Copy after login
		ObjectOutputStream out = null;
Copy after login
		ObjectInputStream in = null;
Copy after login
		T dist = null;
Copy after login
		try {
Copy after login
			out = new ObjectOutputStream(memoryBuffer);
Copy after login
			out.writeObject(src);
Copy after login
			out.flush();
Copy after login
			in = new ObjectInputStream(new ByteArrayInputStream(memoryBuffer.toByteArray()));
Copy after login
			dist = (T) in.readObject();
Copy after login
		} catch (Exception e) {
Copy after login
			throw new RuntimeException(e);
Copy after login
		} finally {
Copy after login
			if (out != null)
Copy after login
				try {
Copy after login
Copy after login
					out.close();
Copy after login
					out = null;
Copy after login
				} catch (IOException e) {
Copy after login
Copy after login
					throw new RuntimeException(e);
Copy after login
Copy after login
				}
Copy after login
Copy after login
			if (in != null)
Copy after login
				try {
Copy after login
Copy after login
					in.close();
Copy after login
					in = null;
Copy after login
				} catch (IOException e) {
Copy after login
Copy after login
					throw new RuntimeException(e);
Copy after login
Copy after login
				}
Copy after login
Copy after login
		}
Copy after login
		return dist;
Copy after login
	}
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
}
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login

看不懂,没关系,直接拿去用就可以了。嘻嘻。

接下来我们测试一下是否能通过这个工具来实现深度克隆。

又是这个可爱的TestCase,可怜的每次都要动他……

import java.util.Date;
Copy after login
Copy after login
Copy after login
Copy after login
import org.junit.Test;
Copy after login
Copy after login
Copy after login
public class TestCase {
Copy after login
Copy after login
Copy after login
<br>
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
	@Test
Copy after login
Copy after login
Copy after login
	public void testCloneTo() {
Copy after login
		Administrator src = new Administrator(new User("Kent", "123456", new Date()), true);
Copy after login
		Administrator dist = BeanUtil.cloneTo(src);
Copy after login
<br>
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
		System.out.println(src == dist);			// false
Copy after login
		System.out.println(src.equals(dist));		// true
Copy after login
<br>
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
		System.out.println(src.getUser() == dist.getUser());		//false ! Well done!
Copy after login
		System.out.println(src.getUser().equals(dist.getUser()));	//true
Copy after login
	}
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
<br>
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
}
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login

好了,无论你的对象有多么的复杂,只要这些对象都能够实现java.lang.Serializable接口,就可以进行克隆,而且这种克隆的机制是JVM完成的,不需要修改实体类的代码,方便多了。

The above is the detailed content of Example tutorial of object cloning (Clone) in Java. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template