通过反射克隆对象,对象复制(克隆)工具类

简介:        最近做的项目中,经常会遇到用视图来操作数据库的,但是页面需要的则是某个实体对象,在controller层查出list 还要把将view对象转化成entity对象。

       最近做的项目中,经常会遇到用视图来操作数据库的,但是页面需要的则是某个实体对象,在controller层查出list<view> 还要把将view对象转化成entity对象。需要写一大堆的get和set方法,而且如果实体增删字段的话,还需要把转化代码再修改一下,让人头疼。


       当我需要操作一个实体对象完成两件不同的事情,这2个方法中会修改实体对象中的属性,第一个方法调用后,再调用第二个方法时,会受影响。为了保证不受影响,必须copy一份属性值一模一样的实体。这时候就需要一个工具类来完成了。


       本着磨刀不误砍柴工的原则,抄起键盘,随手写了一个转换对象的工具类。要求2个对象的字段基本上一致。基本原理就是通过反射,获取set方法,调用源对象的get方法获取源对象的值,再通过目标对象的set方法,将值写入目标对象。具体代码如下:


package com.kaiyuan.common.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 通用对象copy工具类
 * 
 * @author arron
 * @date 2015年1月9日 上午10:50:32
 * @version 1.0
 */
public class ObjectCopyUtil {

    private static final Logger logger = LoggerFactory.getLogger(ObjectCopyUtil.class);
    
	/**
	 * 拷贝对象方法(适合同一类型的对象复制,但结果需强制转换)
	 * 
	 * @throws IllegalAccessException 
	 * @throws InstantiationException 
	 */
	public static Object copy(Object objSource) throws InstantiationException, IllegalAccessException{

		if(null == objSource) return null;//如果源对象为空,则直接返回null
		
		// 获取源对象类型
		Class<?> clazz = objSource.getClass();
		// 获取源对象构造函数
//		Constructor<?> construtctor = clazz.getConstructor();
		// 实例化出目标对象
//		Object objDes = construtctor.newInstance();
		Object objDes = clazz.newInstance();
		
		// 获得源对象所有属性
		Field[] fields = clazz.getDeclaredFields();
		
		// 循环遍历字段,获取字段对应的属性值  
        for ( Field field : fields )  
        {  
            // 如果不为空,设置可见性,然后返回  
            field.setAccessible( true );  
  
            try  
            {  
                // 设置字段可见,即可用get方法获取属性值。  
               field.set(objDes, field.get(objSource));
            }  
            catch ( Exception e )  
            {
            	logger.error("执行{}类的{}属性的set方法时出错。{}",clazz.getSimpleName(),field.getName(),e);
            }  
        }  
        return objDes;
	}
	
	
	/**
	 * 拷贝对象方法(适合同一类型的对象复制)
	 * 
	 * @param objSource 源对象
	 * @param clazz 目标类
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	public static <T> T copy(Object objSource,Class<T> clazz) throws InstantiationException, IllegalAccessException{

		if(null == objSource) return null;//如果源对象为空,则直接返回null
		
		T objDes = clazz.newInstance();
		
		// 获得源对象所有属性
		Field[] fields = clazz.getDeclaredFields();
		
		// 循环遍历字段,获取字段对应的属性值  
		for ( Field field : fields )  
		{  
			// 如果不为空,设置可见性,然后返回  
			field.setAccessible( true );  
			
			try  
			{  
				// 设置字段可见,即可用get方法获取属性值。  
				field.set(objDes, field.get(objSource));
				
			}  
			catch ( Exception e )  
			{
            	logger.error("执行{}类的{}属性的set方法时出错。{}",clazz.getSimpleName(),field.getName(),e);
			}  
		}  
		return objDes;
	}
	
	/**
	 * 拷贝对象方法(适合不同类型的转换)<br/>
	 * 前提是,源类中的所有属性在目标类中都存在
	 * 
	 * @param objSource 源对象
	 * @param clazzSrc 源对象所属class
	 * @param clazzDes 目标class
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	public static <T, K> T copy(K objSource,Class<K> clazzSrc,Class<T> clazzDes) throws InstantiationException, IllegalAccessException{
		
		if(null == objSource) return null;//如果源对象为空,则直接返回null
		
		T objDes = clazzDes.newInstance();
		
		// 获得源对象所有属性
		Field[] fields = clazzSrc.getDeclaredFields();
		
		// 循环遍历字段,获取字段对应的属性值  
		for ( Field field : fields )  
		{  
			// 如果不为空,设置可见性,然后返回  
			field.setAccessible( true );  
			
			try  
			{  
				String fieldName = field.getName();// 属性名
				String firstLetter = fieldName.substring(0, 1).toUpperCase();// 获取属性首字母
	
				// 拼接set方法名
				String setMethodName = "set" + firstLetter + fieldName.substring(1);
				// 获取set方法对象
				Method setMethod = clazzDes.getMethod(setMethodName,new Class[]{field.getType()});
				// 对目标对象调用set方法装入属性值
				setMethod.invoke(objDes, field.get(objSource));
			}  
			catch ( Exception e )  
			{
				logger.error("执行{}类的{}属性的set方法时出错。{}",clazzDes.getSimpleName(),field.getName(),e);
			}  
		}  
		return objDes;
	}
}

       提供了3个方法,适用范围都已经在方法上进行了标注,基本上可以满足需要。


       当然,上面提到的问题,并不一定非得用反射来获取,也可以借助json来实现。先将源对象转化为json,然后再将json转化为目标对象。当然要注重解决一下字段不一致时的转化问题。


目录
相关文章
|
2月前
|
安全 编译器 C++
C++类与对象【对象的初始化和清理】
C++类与对象【对象的初始化和清理】
C++类与对象【对象的初始化和清理】
|
5月前
|
存储
【克隆方法+深浅拷贝】
【克隆方法+深浅拷贝】
35 0
|
11月前
|
存储 JSON JavaScript
Javascript中的对象拷贝(对象复制/克隆)
本文介绍 Javascript中的对象拷贝(对象复制/克隆)的实现方式
211 0
Javascript中的对象拷贝(对象复制/克隆)
|
缓存 算法 安全
【Java对象拷贝机制】使用CGlib实现Bean拷贝(BeanCopier)
【Java对象拷贝机制】使用CGlib实现Bean拷贝(BeanCopier)
429 0
【Java对象拷贝机制】使用CGlib实现Bean拷贝(BeanCopier)
|
PHP 开发者
对象克隆|学习笔记
快速学习对象克隆
84 0
对象克隆|学习笔记
|
Java C语言
Java 对象的克隆Clone和必须了解的浅拷贝与深拷贝
Java 对象的克隆Clone和必须了解的浅拷贝与深拷贝
194 0
Java 对象的克隆Clone和必须了解的浅拷贝与深拷贝
|
Java C语言
克隆、深拷贝与浅拷贝区别
克隆、深拷贝与浅拷贝区别
142 0
|
Java 编译器
Java对象的深克隆与浅克隆(对象复制)(下)
Java对象的深克隆与浅克隆(对象复制)(下)
134 0
Java对象的深克隆与浅克隆(对象复制)(下)
|
Java API
Java对象的深克隆与浅克隆(对象复制)(上)
Java对象的深克隆与浅克隆(对象复制)(上)
105 0
Java对象的深克隆与浅克隆(对象复制)(上)