反射实现java深度克隆

、克隆

有时想得到对象的一个复制品,该复制品的实体是原对象实体的克隆。复制品实体的变化不会引起原对象实体发生变化,这样的复制品称为原对象实体的克隆对象或简称克隆。

1、浅复制(浅克隆)

概念:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。

方法:类implements Cloneable,然后重写clone()方法,在clone()方法中调用super.clone()即可,没有其他操作了

2、深复制(深克隆)

概念:被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。

、克隆的实现

1、通过java的序列化实现克隆,即先对原对象进行序列化,然后再反序列化得到目标对象。

2. 通过反射进行,通过反射,获取对象的内部数据域,然后将数据依次复制,不多说,先上代码

package Reflection;

import java.lang.reflect.Array;

import java.lang.reflect.Field;

import java.lang.reflect.Modifier;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

public class DeepCloneUtil {

public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, InstantiationException {

Person p = new Person("zhanchi",26);

System.out.println(Person.num);

Person p2 = (Person) cloneObject(p);

System.out.println(p2.getName());

System.out.println(p2.getAge());

System.out.println(p.list == p2.list);

System.out.println(p2.list.get(0) == p2);

System.out.println(p.list.get(0) == p2);

System.out.println(Person.num);

}

private static List<Field> getAllFieads(Object o) {

List<Field> fields = new ArrayList<Field>();

if (null == o)

return fields;

Class<?> type = o.getClass();

do {

for (Field f : type.getDeclaredFields()) {

fields.add(f);

}

type = type.getSuperclass();

} while (null != type);

return fields;

}

public static boolean isSimpleObject(Object o) {

Class<?> type = o.getClass();

if (type.isPrimitive()) { // 基本类型

return true;

}

// 不可更改的变量类型 如 String,Long

if (type.equals(String.class))

return true;

if (type.equals(Long.class))

return true;

if(type.equals(Boolean.class))

return true;

if(type.equals(Short.class))

return true;

if(type.equals(Integer.class))

return true;

if(type.equals(Character.class))

return true;

if(type.equals(Float.class))

return true;

if(type.equals(Double.class))

return true;

if(type.equals(Byte.class))

return true;

return false;

}

public static Object cloneObject(Object o) throws IllegalArgumentException, IllegalAccessException, InstantiationException{

if(null == o)

return null;

// 使用Map保存原对象和副本对象之间的结构,防止被多次引用的对象重复重建

Map<Object,Object> map = new HashMap<Object,Object>();

return cloneObject(o,map);

}

private static Object cloneObject(Object o, Map<Object, Object> map)

throws IllegalArgumentException, IllegalAccessException,

InstantiationException {

if (null == o)

return null;

Object newInstance = null;

newInstance = map.get(o);

if (null != newInstance) {

return newInstance;

}

if(isSimpleObject(o))

return o;

// 数组类型

if(o.getClass().isArray()){

return cloneArray(o,map);

}

Class<?> type = o.getClass();

newInstance = type.newInstance();

map.put(o, newInstance);

cloneFields(o, newInstance, map);

return newInstance;

}

private static Object cloneArray(Object o,Map<Object, Object> map) throws IllegalArgumentException, IllegalAccessException, InstantiationException{

if(null == o)

return null;

if(!o.getClass().isArray()){

return cloneObject(o,map);

}

int len = Array.getLength(o);

Object array = Array.newInstance(o.getClass().getComponentType(), len);

map.put(o, array);

for(int i = 0; i < len; i++){

Array.set(array, i, cloneObject(Array.get(o, i),map));

}

return array;

}

private static void cloneFinalObject(Object object, Object newObject, Map<Object, Object> map)throws IllegalArgumentException, IllegalAccessException, InstantiationException{

if(object == null || newObject == null || object == newObject  || !newObject.getClass().equals(newObject.getClass()))

return ;

// 对于final类型的变量

if(null != map.get(newObject)){

return;

}

map.put(newObject, newObject);

cloneFields(object, newObject, map);

return ;

}

private static void cloneFields(Object object, Object newObject,

Map<Object, Object> map) throws SecurityException,

IllegalArgumentException, IllegalAccessException,

InstantiationException {

if(null == object || null == newObject){

return ;

}

List<Field> fields = getAllFieads(object);

for (Field f : fields) {

// 静态变量过滤掉 或者final的变量

if(Modifier.isStatic(f.getModifiers()))

continue;

// 常量

if(Modifier.isFinal(f.getModifiers())){

cloneFinalObject(f.get(object),f.get(newObject),map);

}else{

f.setAccessible(true);

f.set(newObject, cloneObject(f.get(object), map));

}

}

}

}

class Person{

static int num = 0;

Person p;

final List<Person> list = new ArrayList<Person>();

String [] testString = new String[3];

public Person() {

num ++ ;

}

public Person(String name, int age) {

this.age=age;

this.name=name;

p = this;

testString[2] = name;

list.add(p);

list.add(new Person());

num ++ ;

}

public String getName() {

return name;

}

public int getAge() {

return age;

}

@Override

public String toString(){

return "["+this.name+"  "+this.age+"]";

}

private String name;

private int age;

}

时间: 2024-10-27 11:41:10

反射实现java深度克隆的相关文章

java中传值及引伸深度克隆的思考(说白了Java只能传递对象指针)

java中传值及引伸深度克隆的思考 大家都知道java中没有指针.难道java真的没有指针吗?句柄是什么?变量地址在哪里?没有地址的话简直不可想象! java中内存的分配方式有两种,一种是在堆中分配,一种是在堆栈中分配,所有new出来的对象都是在堆中分配的,函数中参数的传递是在栈中分配的.通常情况下堆的内存可以很大,比如32位操作系统中的虚拟内存都可以被堆所使用(当内存紧张的时候甚至硬盘都可以是堆的存储空间),而堆栈的内存分配是有限的. 这和c++中内存分配差不多(c++中还要有另一种方式用于全

JAVA对象任意深度克隆clone工具类分享

原文:JAVA对象任意深度克隆clone工具类分享 源代码下载地址:http://www.zuidaima.com/share/1550463408114688.htm package com.zuidaima.n_app.util; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import jav

【转】Java如何克隆集合——深度拷贝ArrayList和HashSet

原文网址:http://blog.csdn.net/cool_sti/article/details/21658521 原英文链接:http://javarevisited.blogspot.hk/2014/03/how-to-clone-collection-in-java-deep-copy-vs-shallow.html 程序员通常会误用集合类(如List.Set.ArrayList.HashSet)所提供的拷贝构造函数或其它方法来完成集合的拷贝.值得记住的一点是,Java中集合提供的拷贝

Java中深度克隆和浅度克隆

一:使用目的: 就是为了快速构造一个和已有对象相同的副本.如果需要克隆对象,一般需要先创建一个对象,然后将原对象中的数据导入到新创建的对象中去,而不用根据已有对象进行手动赋值操作. 二:Object中的clone()方法 protected native Object clone() throws CloneNotSupportedException; 说明:1.这是一个navtive方法  2.要使用该方法必须继承Object类,因为修饰符为protected  3.返回值为Object,需要

JAVA对象的深度克隆

有时候,我们需要把对象A的所有值复制给对象B(B = A),但是这样用等号给赋值你会发现,当B中的某个对象值改变时,同时也会修改到A中相应对象的值! 也许你会说,用clone()不就行了?!你的想法只对了一半,因为用clone()时,除了基础数据和String类型的不受影响外,其他复杂类型(如集合.对象等)还是会受到影响的!除非你对每个对象里的复杂类型又进行了clone(),但是如果一个对象的层次非常深,那么clone()起来非常复杂,还有可能出现遗漏! 既然用等号和clone()复制对象都会对

深度克隆:ObjectInputStream、ObjectOutputStream和ByteArrayOutputStream

下面一段深度克隆的源码,不甚理解,查查记录下来 bout = new ByteArrayOutputStream(); ObjectOutputStream oos = null; ObjectInputStream ois = null; oos = new ObjectOutputStream(bout); oos.writeObject(oldValue); //将指定的对象写入 ObjectOutputStream ByteArrayInputStream bin = new ByteA

Java深度理解——Java字节代码的操纵

导读:Java作为业界应用最为广泛的语言之一,深得众多软件厂商和开发者的推崇,更是被包括Oracle在内的众多JCP成员积极地推动发展.但是对于 Java语言的深度理解和运用,毕竟是很少会有人涉及的话题.InfoQ中文站特地邀请IBM高级工程师成富为大家撰写这个<Java深度历险>专栏,旨在就Java的一些深度和高级特性分享他的经验.在一般的Java应用开发过程中,开发人员使用Java的方式比较简单.打开惯用的IDE,编写Java源代码,再利用IDE提供的功能直接运行 Java 程序就可以了.

深入浅出设计模式 ------ Prototype(原型模式)之深度克隆

继上篇深入浅出设计模式 ------ Prototype(原型模式)的浅克隆实现, 本文进入Prototype(原型模式)的进阶篇----深度克隆. 深度克隆 ---- 序列化方式实现 把对象写到流里的过程是序列化(Serilization)过程,而把对象从流中读出来的过程则叫做反序列化(Deserialization).写在流里的是对象的一个克隆(新的, 独立的), 而原对象仍存在于JVM内存模型里.因此, 以下代码采用序列化方式实现深度克隆. 第一步: 将上篇的代码做些许改动, 加入对象引用

Java对象克隆(Clone)及Cloneable接口、Serializable接口的深入探讨

Java对象克隆(Clone)及Cloneable接口.Serializable接口的深入探讨 Part I 没啥好说的,直接开始Part II吧. Part II 谈到了对象的克隆,就不得不说为什么要对对象进行克隆.Java中所有的对象都是保存在堆中,而堆是供全局共享的.也就是说,如果同一个Java程序的不同方法,只要能拿到某个对象的引用,引用者就可以随意的修改对象的内部数据(前提是这个对象的内部数据通过get/set方法曝露出来).有的时候,我们编写的代码想让调用者只获得该对象的一个拷贝(也