有时候需要深度复制任意的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.beans包中,有两个好东西,XMLEncoder和XMLDecoder。从XML存取对象真是太费力气啦。做了小工具类,以后可以用用了。本文介绍了这两个可以把JAVA对象序列化保存为XML文件的工具类。
java项目源码
时间序列分析 一个时间序列通常由4种要素组成:趋势、季节变动、循环波动和不规则波动。 趋势:是时间序列在长时期内呈现出来的持续向上或持续向下的变动。 季节变动:是时间序列在一年内重复出现的周期性波动。...
Gson 可以处理任意 Java 对象,包括您没有源代码的现有对象。 有一些开源项目可以将 Java 对象转换为 JSON。然而,大多数都要求您在类中放置 Java 注释;如果您无法访问源代码,则无法执行某些操作。大多数也不完全...
Gson这个Java类库可以把Java对象转换成JSON,也可以把JSON字符串转换成一个相等的Java对象。Gson支持任意复杂Java对象包括没有源代码的对象。
任意 文件 拷贝 任意 文件 拷贝 任意 文件 拷贝 任意 文件 拷贝
java转换音频格式,以满足特定音频要求(比如百度语音识别)。底层就是ffmpeg命令, 它支持的都支持,也支持windows和Linux环境。
Gson可以使用任意Java对象Gson Gson是一个Java库,可用于将Java对象转换为其JSON表示形式。 它也可以用于将JSON字符串转换为等效的Java对象。 Gson可以处理任意Java对象,包括您没有源代码的预先存在的对象。 有一些...
java 打印任意一年日历 java 打印任意一年日历
求树的深度 C++ 递归构造树, 递归实现时的显示,先序遍历, 孩子兄弟列表
Java音频视频编码器,本文实例将任何音频格式转换为MP3格式 您还可以调整视频大小,更改其大小和比例等 本文实例实用于任何Windows,MacOS,Linux系统 附:完整jar项目,完善的demo,详细的注释,简单易操作
Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。
json-rpc-for-java,是仅仅不到100行的javascript代码和不到10个java文件实现的超级轻量级的通过 javaScript快速调用java对象并返回任意对象的轻量级框架,并且支持级联调用,也就是说不需要额外 的JavaScript编程,...
本专栏主要为Java程序设计(基础)实验报告和Java程序设计(进阶)实验报告,基础篇有JAVA环境搭建、Java语言基础、方法和数组、面向对象基础、Java常用类、继承与接口、成员访问控制与异常、JavaFX程序设计、Java...
继《JavaScript高级应用与实践》之后推出的json-rpc-for-java开源代码,是仅仅100行的javascript代码和不到10个java文件实现的超级轻量级的通过 javaScript快速调用java对象并返回任意对象的轻量级框架,并且支持...
支持输入任意文件名,任意目录下的文件拷贝。
Java.io 包几乎包含了所有操作输入、输出需要的类。所有这些流类代表了输入源和输出目标。 Java.io 包中的流支持很多种格式,比如:基本类型、对象、本地化字符集等等
java求任意数的阶乘,java求任意数的阶乘,java求任意数的阶乘
py4j:Py4J使Python程序能够动态访问任意Java对象
java注解实现通用Excel中文表格转实体对象列表,支持中文表头,在Excel数据导入使用的通用工具类,代码简洁优雅 。基于注解实现的支持中文表头的读取Excel数据并转换为实体对象列表的工具类,使用该工具类可将Excel...