`
napp
  • 浏览: 3445 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
文章分类
社区版块
存档分类
最新评论

任意JAVA对象的深度拷贝

阅读更多
有时候需要深度复制任意的JAVA对象(无论是否实现Cloneable接口或序列化接口),但发现BeanUtils不太好用,因此写了以下工具类来进行深度复制。
package com.n_app.util;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 克隆工具类
 * @author lujijiang@gmail.com
 *
 */
public class Clone {
	/**
	 * 无需进行复制的特殊类型数组
	 */
	static Class[] needlessCloneClasses = new Class[]{String.class,Boolean.class,Character.class,Byte.class,Short.class,
		Integer.class,Long.class,Float.class,Double.class,Void.class,Object.class,Class.class
	};
	/**
	 * 判断该类型对象是否无需复制
	 * @param c 指定类型
	 * @return 如果不需要复制则返回真,否则返回假
	 */
	private static boolean isNeedlessClone(Class c){
		if(c.isPrimitive()){//基本类型
			return true;
		}
		for(Class tmp:needlessCloneClasses){//是否在无需复制类型数组里
			if(c.equals(tmp)){
				return true;
			}
		}
		return false;
	}
	
	/**
	 * 尝试创建新对象
	 * @param c 原始对象
	 * @return 新的对象
	 * @throws IllegalAccessException
	 */
	private static Object createObject(Object value) throws IllegalAccessException{
			try {
				return value.getClass().newInstance();
			} catch (InstantiationException e) {
				return null;
			} catch (IllegalAccessException e) {
				throw e;
			}
	}
	
	/**
	 * 复制对象数据
	 * @param value 原始对象
	 * @param level 复制深度。小于0为无限深度,即将深入到最基本类型和Object类级别的数据复制;
	 * 大于0则按照其值复制到指定深度的数据,等于0则直接返回对象本身而不进行任何复制行为。
	 * @return 返回复制后的对象
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 */
	public static Object clone(Object value,int level) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException{
		if(value==null){
			return null;
		}
		if(level==0){
			return value;
		}
		Class c = value.getClass();
		if(isNeedlessClone(c)){
			return value;
		}
		level--;
		if(value instanceof Collection){//复制新的集合
			Collection tmp = (Collection)c.newInstance();
			for(Object v:(Collection)value){
				tmp.add(clone(v,level));//深度复制
			}
			value = tmp;
		}
		else if(c.isArray()){//复制新的Array
			//首先判断是否为基本数据类型
			if(c.equals(int[].class)){
				int[] old = (int[])value;
				value = (int[])Arrays.copyOf(old, old.length);
			}
			else if(c.equals(short[].class)){
				short[] old = (short[])value;
				value = (short[])Arrays.copyOf(old, old.length);
			}
			else if(c.equals(char[].class)){
				char[] old = (char[])value;
				value = (char[])Arrays.copyOf(old, old.length);
			}
			else if(c.equals(float[].class)){
				float[] old = (float[])value;
				value = (float[])Arrays.copyOf(old, old.length);
			}
			else if(c.equals(double[].class)){
				double[] old = (double[])value;
				value = (double[])Arrays.copyOf(old, old.length);
			}
			else if(c.equals(long[].class)){
				long[] old = (long[])value;
				value = (long[])Arrays.copyOf(old, old.length);
			}
			else if(c.equals(boolean[].class)){
				boolean[] old = (boolean[])value;
				value = (boolean[])Arrays.copyOf(old, old.length);
			}
			else if(c.equals(byte[].class)){
				byte[] old = (byte[])value;
				value = (byte[])Arrays.copyOf(old, old.length);
			}
			else {
				Object[] old = (Object[])value;
				Object[] tmp = (Object[])Arrays.copyOf(old, old.length, old.getClass());
				for(int i = 0;i<old.length;i++){
					tmp[i] = clone(old[i],level);
				}
				value = tmp;
			}
		}
		else if(value instanceof Map){//复制新的MAP
			Map tmp = (Map)c.newInstance();
			Map org = (Map)value;
			for(Object key:org.keySet()){
				tmp.put(key, clone(org.get(key),level));//深度复制
			}
			value = tmp;
		}
		else {
			Object tmp = createObject(value);
			if(tmp==null){//无法创建新实例则返回对象本身,没有克隆
				return value;
			}
			Set<Field> fields = new HashSet<Field>();
			while(c!=null&&!c.equals(Object.class)){
				fields.addAll(Arrays.asList(c.getDeclaredFields()));
				c = c.getSuperclass();
			}
			for(Field field:fields){
				if(!Modifier.isFinal(field.getModifiers())){//仅复制非final字段
					field.setAccessible(true);
					field.set(tmp, clone(field.get(value),level));//深度复制
				}
			}
			value = tmp;
		}
		return value;
	}
	
	/**
	 * 浅表复制对象
	 * @param value 原始对象
	 * @return 复制后的对象,只复制一层
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 */
	public static Object clone(Object value) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException{
		return clone(value,1);
	}
	
	/**
	 * 深度复制对象
	 * @param value 原始对象
	 * @return 复制后的对象
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 */
	public static Object deepClone(Object value) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException{
		return clone(value,-1);
	}
}


注:此复制方法是非安全的,对于某些特殊情况将无法复制其值,比如final字段和无空构造方法的类型等,仅适用于复制普通DTO、POJO等,其它场合请慎用。
分享到:
评论

相关推荐

    java深度复制源代码

    ### Java深度复制源代码知识点解析 ...综上所述,该Java深度复制工具类通过反射机制实现了JavaBean对象的深度复制,适用于多种场景下的对象复制需求,但在实际应用中需要注意性能和特殊对象结构的处理问题。

    Java进阶知识

    Java是一种广泛使用的编程语言,尤其在企业级应用和服务器端开发...总结来说,Java进阶知识包括批处理文件的运用、对象拷贝的深度理解以及内存管理的优化策略。理解并掌握这些知识,将有助于提升Java编程的效率和质量。

    二十三种设计模式【PDF版】

    所以很少存在简单重复的工作,加上Java 代码的精炼性和面向对象纯洁性(设计模式是 java 的灵魂),编程工作将变成一个让你时刻 体验创造快感的激动人心的过程. 为能和大家能共同探讨"设计模式",我将自己在学习中的心得...

    经典Python面试题之Python基础篇.docx

    浅拷贝只复制对象引用,深拷贝复制整个对象及子对象,防止原对象修改影响副本。 27. Python垃圾回收: 自动回收不再使用的内存,通过引用计数和垃圾收集算法实现。 28. 可变类型与不可变类型: 可变类型如列表...

    Python从入门到进阶知识手册 1885页

    - **浅拷贝**:创建一个新的对象,但对象内的元素指向原对象中的元素。 - **深拷贝**:完全复制一个对象及其内部的所有对象。 #### 位与字节的关系 - 1字节(Byte) = 8位(bit)。 #### b、B、KB、MB、GB的关系 - 1 b...

    经典python面试题

    - **浅拷贝**:只复制引用,修改会影响原对象。 - **深拷贝**:完全复制,修改不会影响原对象。 - 应用场景:当需要复制复杂对象时选择合适的方式。 #### 28. Python垃圾回收机制 - 主要依赖引用计数,当引用计数...

    程序员面试题精选100题.doc

    - **状态转移方程**:对于任意位置i,都有dp[i] = max(dp[i-1]+nums[i], nums[i])。 - **优化技巧**:为了减少空间复杂度,可以使用滚动数组或者仅使用两个变量来记录前一个状态和当前状态。 ### 4. 在二元树中找出...

    2021-2022计算机二级等级考试试题及答案No.9204.docx

    - **原因**:数据不一致的主要原因是数据冗余,即同一数据在数据库中存在多份拷贝。 - **解决方案**:通过实施数据完整性控制措施,比如唯一约束、外键约束等,来避免数据冗余,从而提高数据的一致性。 #### 知识点...

    《剑指Offer》题目及代码.pdf

    1. 赋值运算函数:通常指的是复制构造函数,负责实现对象的深拷贝。在C++中,如果类中包含动态分配的资源,则必须重载赋值运算函数以确保资源被正确复制。 2. 单例设计模式:保证一个类只有一个实例,并提供一个...

    Microsoft.Net常见问题集锦

    静态成员只有一份拷贝供所有对象共享,通常用于存储不会随对象状态变化而变化的信息。 22. **简述 private、protected、public、internal 修饰符的访问权限。** - `private`:仅在声明它的类内部可见。 - `...

    oracle学习文档 笔记 全面 深刻 详细 通俗易懂 doc word格式 清晰 连接字符串

    其二、技术层次深:如果期望进入IT服务或者产品公司(类似毕博、DELL、IBM等),Oracle技术能够帮助提高就业的深度。 其三、职业方向多:Oracle数据库管理方向、Oracle开发及系统架构方向、Oracle数据建模数据仓库等...

Global site tag (gtag.js) - Google Analytics