ホームページ > Java > &#&チュートリアル > Java でのオブジェクトの複製 (Clone) のチュートリアルの例

Java でのオブジェクトの複製 (Clone) のチュートリアルの例

零下一度
リリース: 2017-07-19 10:00:01
オリジナル
1563 人が閲覧しました

パート II<br>

オブジェクトのクローン作成について話すと、なぜオブジェクトをクローンする必要があるのか​​について話さなければなりません。 Java のすべてのオブジェクトはヒープに格納され、ヒープはグローバルに共有されます。言い換えれば、同じ Java プログラムの異なるメソッドがオブジェクトへの参照を取得できる場合、リファラーはオブジェクトの内部データを自由に変更できます (オブジェクトの内部データが get/set メソッドを通じて公開されている場合)。 。私たちが作成するコードでは、呼び出し元にオブジェクトのコピーを 1 つだけ取得してもらいたいことがあります (つまり、まったく同じ内容のオブジェクトですが、メモリ内にそのようなオブジェクトが 2 つあります)。これを行う方法はありますか?もちろんクローンです。

パート III

まず第一に、私たちはプログラマーであり、もちろんプログラマーの言語でコミュニケーションを行います。

上記のコードは、User クラスを構築し、java.lang.Cloneable インターフェースを実装します。名前が示すように、Cloneable は、このクラスを複製できることを意味します。

まず、java.lang.Cloneable インターフェースが何を持っているかを見てみましょう。 ❤️そうです、多くの鶏の腸を除いて、このインターフェイスはメソッド シグネチャを定義していません。言い換えれば、オブジェクトのクローンを作成したいのですが、メソッドが提供されません。じゃあ何をすればいいの?心配しないでください、まだ全能の Object クラスが存在します。彼はすべてのクラスの祖先 (神のような存在) であることを忘れないでください。

import java.util.Date;
ログイン後にコピー
ログイン後にコピー
public class User implements Cloneable {
ログイン後にコピー
	private String username;
ログイン後にコピー
	private String password;
ログイン後にコピー
	private Date birthdate;
ログイン後にコピー
	public User(String username, String password, Date birthdate) {
ログイン後にコピー
		this.username = username;
ログイン後にコピー
		this.password = password;
ログイン後にコピー
		this.birthdate = birthdate;
ログイン後にコピー
	}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
	@Override
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
	protected Object clone() throws CloneNotSupportedException {
ログイン後にコピー
		return super.clone();
ログイン後にコピー
	}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
	@Override
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
	public int hashCode() {
ログイン後にコピー
		// 省略equals的实现(可用eclipse自动生成)
ログイン後にコピー
ログイン後にコピー
	}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
	@Override
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
	public boolean equals(Object obj) {
ログイン後にコピー
		// 省略equals的实现(可用eclipse自动生成)
ログイン後にコピー
ログイン後にコピー
	}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
	// 省略一大堆get/set方法
ログイン後にコピー
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
/*
ログイン後にコピー
ログイン後にコピー
 * @(#)Cloneable.java	1.17 05/11/17
ログイン後にコピー
 *
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
ログイン後にコピー
ログイン後にコピー
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
ログイン後にコピー
ログイン後にコピー
 */
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
package java.lang;
ログイン後にコピー
ログイン後にコピー
/**
ログイン後にコピー
ログイン後にコピー
 * A class implements the Cloneable interface to
ログイン後にコピー
 * indicate to the {@link java.lang.Object#clone()} method that it
ログイン後にコピー
 * is legal for that method to make a
ログイン後にコピー
 * field-for-field copy of instances of that class.
ログイン後にコピー
 *
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
 * Invoking Object's clone method on an instance that does not implement the
ログイン後にコピー
 

 * Cloneable interface results in the exception
ログイン後にコピー
 * CloneNotSupportedException being thrown.
ログイン後にコピー
 *
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
 * By convention, classes that implement this interface should override
ログイン後にコピー
 * Object.clone (which is protected) with a public method.
ログイン後にコピー
 

 * See {@link java.lang.Object#clone()} for details on overriding this
ログイン後にコピー
 * method.
ログイン後にコピー
 *
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
 * Note that this interface does not contain the clone method.
ログイン後にコピー
 * Therefore, it is not possible to clone an object merely by virtue of the
ログイン後にコピー
 * fact that it implements this interface.  Even if the clone method is invoked
ログイン後にコピー
 * reflectively, there is no guarantee that it will succeed.
ログイン後にコピー
 *
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
 * @author  unascribed
ログイン後にコピー
ログイン後にコピー
 * @version 1.17, 11/17/05
ログイン後にコピー
 * @see     java.lang.CloneNotSupportedException
ログイン後にコピー
 

 * @see     java.lang.Object#clone()
ログイン後にコピー
 * @since   JDK1.0
ログイン後にコピー
ログイン後にコピー
 */
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
public interface Cloneable {
ログイン後にコピー
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
/*
ログイン後にコピー
ログイン後にコピー
 * @(#)Object.java	1.73 06/03/30
ログイン後にコピー
 *
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
ログイン後にコピー
ログイン後にコピー
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
ログイン後にコピー
ログイン後にコピー
 */
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
 

package java.lang;
ログイン後にコピー
ログイン後にコピー
/**
ログイン後にコピー
ログイン後にコピー
 * Class Object is the root of the class hierarchy.
ログイン後にコピー
 * Every class has Object as a superclass. All objects,
ログイン後にコピー
 * including arrays, implement the methods of this class.
ログイン後にコピー
 *
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
 * @author  unascribed
ログイン後にコピー
ログイン後にコピー
 * @version 1.73, 03/30/06
ログイン後にコピー
 * @see     java.lang.Class
ログイン後にコピー
 * @since   JDK1.0
ログイン後にコピー
ログイン後にコピー
 */
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
public class Object {
ログイン後にコピー
    <br>
ログイン後にコピー
   // 省略N多的代码
ログイン後にコピー
    /**
ログイン後にコピー
呵呵,又是一大串的鸡肠,别以为我是来凑字数的,这些都是Sun公司Java开发人员写的技术文章,多看看話すことを減らしましょう。

はい、これは確かに奥深いものですが、それでも活用する必要があります。さらに、彼の手法は保護されており、明らかに私たちに利用するよう求めています。

引き続き以下のテストコードを見てください。

メソッド、牛です、実行結果は期待通りですアドレスは違いますが内容は同じです。

パート IV

上の例を通して、オブジェクトを複製するには実際には 2 つのステップがあることがわかります。

1. クラスに java.lang.Cloneable インターフェースを実装します。 2. オーバーライドします。 Object クラスの clone() メソッドを (オーバーライド) します。

しかし、本当にそんなに単純なのでしょうか?以下のコードをもう一度見てください。

上記は User クラスのオブジェクトを保持する Administrator クラスを定義しています。次に、Administrator オブジェクトの複製の効果を見てみましょう。 Rrereerreerrreerreerreerreerreerreerreerreerreerreerreerreerreerreerreerreerreerreerreerreerree
     * Creates and returns a copy of this object.  The precise meaning
ログイン後にコピー
re hehehe!何か問題が発生しました。 Java をマスターするのはとても簡単です。

ここで、浅いクローンと深いクローンという 2 つの専門用語を紹介します。

いわゆるシャロー クローンは、名前が示すように、非常に表面的なクローンです。管理者オブジェクトをクローンする場合は、それ自体とそれに含まれるすべてのオブジェクトの

参照アドレス

のみをクローンします。

そして、ディープ クローン作成はシャロー クローン作成ではありません。それ自体を除くすべてのオブジェクト (それ自体に含まれるすべての

オブジェクト インスタンス

を含む) をクローンします。ディープ クローン作成のレベルについては、特定のニーズによって決まります。「N レベル クローン作成」という言葉もあります。

ただし、浅いクローンでも深いクローンでも、すべてのプリミティブ型のデータは元の値でクローンされます。結局のところ、それらはオブジェクトではなく、ヒープに格納されません。注: 基本データ型には、対応するラッパー クラスが含まれません。

オブジェクトをディープクローンしたい場合は、次のように Administrator クラスを変更できます。

RREERREERREERREERREERREERREE

Boolean は値をキャッシュするため、Boolean オブジェクトを複製する必要はありません。また、Boolean クラスは java.lang.Cloneable インターフェイスを実装しません。

パート 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;
ログイン後にコピー
import java.io.ByteArrayOutputStream;
ログイン後にコピー
import java.io.IOException;
ログイン後にコピー
import java.io.ObjectInputStream;
ログイン後にコピー
import java.io.ObjectOutputStream;
ログイン後にコピー
public abstract class BeanUtil {
ログイン後にコピー
	@SuppressWarnings("unchecked")
ログイン後にコピー
	public static  T cloneTo(T src) throws RuntimeException {
ログイン後にコピー
		ByteArrayOutputStream memoryBuffer = new ByteArrayOutputStream();
ログイン後にコピー
		ObjectOutputStream out = null;
ログイン後にコピー
		ObjectInputStream in = null;
ログイン後にコピー
		T dist = null;
ログイン後にコピー
		try {
ログイン後にコピー
			out = new ObjectOutputStream(memoryBuffer);
ログイン後にコピー
			out.writeObject(src);
ログイン後にコピー
			out.flush();
ログイン後にコピー
			in = new ObjectInputStream(new ByteArrayInputStream(memoryBuffer.toByteArray()));
ログイン後にコピー
			dist = (T) in.readObject();
ログイン後にコピー
		} catch (Exception e) {
ログイン後にコピー
			throw new RuntimeException(e);
ログイン後にコピー
		} finally {
ログイン後にコピー
			if (out != null)
ログイン後にコピー
				try {
ログイン後にコピー
ログイン後にコピー
					out.close();
ログイン後にコピー
					out = null;
ログイン後にコピー
				} catch (IOException e) {
ログイン後にコピー
ログイン後にコピー
					throw new RuntimeException(e);
ログイン後にコピー
ログイン後にコピー
				}
ログイン後にコピー
ログイン後にコピー
			if (in != null)
ログイン後にコピー
				try {
ログイン後にコピー
ログイン後にコピー
					in.close();
ログイン後にコピー
					in = null;
ログイン後にコピー
				} catch (IOException e) {
ログイン後にコピー
ログイン後にコピー
					throw new RuntimeException(e);
ログイン後にコピー
ログイン後にコピー
				}
ログイン後にコピー
ログイン後にコピー
		}
ログイン後にコピー
		return dist;
ログイン後にコピー
	}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

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

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

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

import java.util.Date;
ログイン後にコピー
ログイン後にコピー
import org.junit.Test;
ログイン後にコピー
public class TestCase {
ログイン後にコピー
<br>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
	@Test
ログイン後にコピー
	public void testCloneTo() {
ログイン後にコピー
		Administrator src = new Administrator(new User("Kent", "123456", new Date()), true);
ログイン後にコピー
		Administrator dist = BeanUtil.cloneTo(src);
ログイン後にコピー
<br>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
		System.out.println(src == dist);			// false
ログイン後にコピー
		System.out.println(src.equals(dist));		// true
ログイン後にコピー
<br>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
		System.out.println(src.getUser() == dist.getUser());		//false ! Well done!
ログイン後にコピー
		System.out.println(src.getUser().equals(dist.getUser()));	//true
ログイン後にコピー
	}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
<br>
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

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

以上がJava でのオブジェクトの複製 (Clone) のチュートリアルの例の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート