`

JAVA对象属性复制

阅读更多

        编程过程中,有些时候某些不同的类有相同的字段,可能会遇到同时给他们赋值的情况。简单的时候,可以写重复的代码,重复太多的时候,就不如给一个赋值完,直接复制给另一个对象。
        上面这种情况在数据库的实体类中比较常见。

        java对象之间属性值复制在许多开源框架中也有实现,在这里介绍自实现、Spring、apache commons-beanutils三种实现方式。

一.自己实现简单的对象属性复制
CopyUtil01.java

package com.bijian.study;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;

/*
 * 复制的对象必须同时拥有setter和getter方法,只有一个的时候会报异常,都没有的时候就不复制
 */
public class CopyUtil01 {
    
    public static void Copy(Object source, Object dest) throws Exception {
        //获取属性
        BeanInfo sourceBean = Introspector.getBeanInfo(source.getClass(), java.lang.Object.class);
        PropertyDescriptor[] sourceProperty = sourceBean.getPropertyDescriptors();

        BeanInfo destBean = Introspector.getBeanInfo(dest.getClass(), java.lang.Object.class);
        PropertyDescriptor[] destProperty = destBean.getPropertyDescriptors();

        try {
            for (int i = 0; i < sourceProperty.length; i++) {

                for (int j = 0; j < destProperty.length; j++) {

                    if (sourceProperty[i].getName().equals(destProperty[j].getName())) {
                        //调用source的getter方法和dest的setter方法
                        destProperty[j].getWriteMethod().invoke(dest, sourceProperty[i].getReadMethod().invoke(source));
                        break;
                    }
                }
            }
        } catch (Exception e) {
            throw new Exception("属性复制失败:" + e.getMessage());
        }
    }
}

 

CopyUtil02.java

package com.bijian.study;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.Set;

/*
 * 该方法接收两个参数,一个是复制的源对象——要复制的对象,一个是复制的目标对象——对象副本。
 * 当然这个方法也可以在两个不同对象间使用,这时候只要目标对象和对象具有一个或多个相同类型及名称的属性,那么就会把源对象的属性值赋给目标对象的属性
 */
public class CopyUtil02 {

	public static <T> T getBean(T TargetBean, T SourceBean) throws Exception {
		if (TargetBean == null)
			return null;
		Field[] tFields = TargetBean.getClass().getDeclaredFields();
		Field[] sFields = SourceBean.getClass().getDeclaredFields();
		try {
			for (Field field : tFields) {
				String fieldName = field.getName();
				if (fieldName.equals("serialVersionUID"))
					continue;
				if (field.getType() == Map.class)
					continue;
				if (field.getType() == Set.class)
					continue;
				if (field.getType() == List.class)
					continue;
				for (Field sField : sFields) {
					if (!sField.getName().equals(fieldName)) {
						continue;
					}
					Class type = field.getType();
					String setName = getSetMethodName(fieldName);
					Method tMethod = TargetBean.getClass().getMethod(setName, new Class[] { type });
					String getName = getGetMethodName(fieldName);
					Method sMethod = SourceBean.getClass().getMethod(getName, null);
					Object setterValue = sMethod.invoke(SourceBean, null);
					tMethod.invoke(TargetBean, new Object[] { setterValue });
				}
			}
		} catch (Exception e) {
			throw new Exception("设置参数信息发生异常", e);
		}
		return TargetBean;
	}

	private static String getGetMethodName(String fieldName) {
		fieldName = replaceFirstCharToUpper(fieldName);
		return "get" + fieldName;
	}

	private static String getSetMethodName(String fieldName) {
		fieldName = replaceFirstCharToUpper(fieldName);
		return "set" + fieldName;
	}

	private static String replaceFirstCharToUpper(String fieldName) {
		char[] chars = new char[1];
		chars[0] = fieldName.charAt(0);
		String temp = new String(chars);
		if (chars[0] >= 'a' && chars[0] <= 'z') {
			fieldName = fieldName.replaceFirst(temp, temp.toUpperCase());
		}
		return fieldName;
	}
}

 

CopyUtil03.java

package com.bijian.study;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

/*
 * 采用反射,通过源对象getter 方法获取属性值,并通过目标对象的setter方法设置到目标对象中去
 */
public class CopyUtil03 {

	/**
	 * 利用反射实现对象之间属性复制
	 * @param from
	 * @param to
	 */
	public static void copyProperties(Object from, Object to) throws Exception {
		copyPropertiesExclude(from, to, null);
	}
	
	/**
	 * 复制对象属性
	 * @param from
	 * @param to
	 * @param excludsArray 排除属性列表
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public static void copyPropertiesExclude(Object from, Object to, String[] excludsArray) throws Exception {
		List<String> excludesList = null;
		if(excludsArray != null && excludsArray.length > 0) {
			excludesList = Arrays.asList(excludsArray);	//构造列表对象
		}
		Method[] fromMethods = from.getClass().getDeclaredMethods();
		Method[] toMethods = to.getClass().getDeclaredMethods();
		Method fromMethod = null, toMethod = null;
		String fromMethodName = null, toMethodName = null;
		for (int i = 0; i < fromMethods.length; i++) {
			fromMethod = fromMethods[i];
			fromMethodName = fromMethod.getName();
			if (!fromMethodName.contains("get"))
				continue;
			//排除列表检测
			if(excludesList != null && excludesList.contains(fromMethodName.substring(3).toLowerCase())) {
				continue;
			}
			toMethodName = "set" + fromMethodName.substring(3);
			toMethod = findMethodByName(toMethods, toMethodName);
			if (toMethod == null)
				continue;
			Object value = fromMethod.invoke(from, new Object[0]);
			if(value == null)
				continue;
			//集合类判空处理
			if(value instanceof Collection) {
				Collection newValue = (Collection)value;
				if(newValue.size() <= 0)
					continue;
			}
			toMethod.invoke(to, new Object[] {value});
		}
	}
	
	/**
	 * 对象属性值复制,仅复制指定名称的属性值
	 * @param from
	 * @param to
	 * @param includsArray
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public static void copyPropertiesInclude(Object from, Object to, String[] includsArray) throws Exception {
		List<String> includesList = null;
		if(includsArray != null && includsArray.length > 0) {
			includesList = Arrays.asList(includsArray);	//构造列表对象
		} else {
			return;
		}
		Method[] fromMethods = from.getClass().getDeclaredMethods();
		Method[] toMethods = to.getClass().getDeclaredMethods();
		Method fromMethod = null, toMethod = null;
		String fromMethodName = null, toMethodName = null;
		for (int i = 0; i < fromMethods.length; i++) {
			fromMethod = fromMethods[i];
			fromMethodName = fromMethod.getName();
			if (!fromMethodName.contains("get"))
				continue;
			//排除列表检测
			String str = fromMethodName.substring(3);
			if(!includesList.contains(str.substring(0,1).toLowerCase() + str.substring(1))) {
				continue;
			}
			toMethodName = "set" + fromMethodName.substring(3);
			toMethod = findMethodByName(toMethods, toMethodName);
			if (toMethod == null)
				continue;
			Object value = fromMethod.invoke(from, new Object[0]);
			if(value == null)
				continue;
			//集合类判空处理
			if(value instanceof Collection) {
				Collection newValue = (Collection)value;
				if(newValue.size() <= 0)
					continue;
			}
			toMethod.invoke(to, new Object[] {value});
		}
	}
	
	/**
	 * 从方法数组中获取指定名称的方法
	 * 
	 * @param methods
	 * @param name
	 * @return
	 */
	public static Method findMethodByName(Method[] methods, String name) {
		for (int j = 0; j < methods.length; j++) {
			if (methods[j].getName().equals(name))
				return methods[j];
		}
		return null;
	}
}

 

O1.java

package com.bijian.study;

public class O1 {
    private String aac001;
    private String aac002;
    private Double ddd001;
    
    public String getAac001() {
            return aac001;
    }
    public void setAac001(String aac001) {
            this.aac001 = aac001;
    }
    public String getAac002() {
            return aac002;
    }
    public void setAac002(String aac002) {
            this.aac002 = aac002;
    }
    public Double getDdd001() {
            return ddd001;
    }
    public void setDdd001(Double ddd001) {
            this.ddd001 = ddd001;
    }
}

 

O2.java

package com.bijian.study;

public class O2 {
    private String aac001;
    private String aac002;
    private Double ddd001;
    private String aac003;
    private String aac004;
    public String getAac002() {
            return aac002;
    }
    public void setAac002(String aac002) {
            this.aac002 = aac002;
    }
    public String getAac001() {
            return aac001;
    }
    public void setAac001(String aac001) {
            this.aac001 = aac001;
    }
    public String getAac003() {
            return aac003;
    }
    public void setAac003(String aac003) {
            this.aac003 = aac003;
    }
    public String getAac004() {
            return aac004;
    }
    public void setAac004(String aac004) {
            this.aac004 = aac004;
    }
    public Double getDdd001() {
            return ddd001;
    }
    public void setDdd001(Double ddd001) {
            this.ddd001 = ddd001;
    }
}

 

CopyJunitTest.java

package com.bijian.study;

import java.beans.Introspector;
import java.beans.PropertyDescriptor;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

public class CopyJunitTest {
	O1 o1 = null;
	O2 o2 = null;

	@Before
	public void setUp() {
		this.o1 = new O1();
		this.o2 = new O2();

		this.o1.setAac001("00007");
		this.o1.setAac002("国产零零零零七");
		this.o1.setDdd001(Double.valueOf(3.141592653589793D));
	}

	@Test
	public void test_copyUtil01() {
		try {
			CopyUtil01.Copy(this.o1, this.o2);
			System.out.println("CopyUtil01单元测试");

			System.out.println("-------------源对象o1----------------");
			showObjectPropertyValue(this.o1);
			System.out.println("-------------目标对象o2----------------");
			showObjectPropertyValue(this.o2);
			System.out.println();
		} catch (Exception e) {
			Assert.fail();
		}
	}

	@Test
	public void test_copyUtil02() {
		try {
			this.o2 = ((O2) CopyUtil02.getBean(this.o2, this.o1));
			System.out.println("CopyUtil02单元测试");
			System.out.println("-------------源对象o1----------------");
			showObjectPropertyValue(this.o1);
			System.out.println("-------------目标对象o2----------------");
			showObjectPropertyValue(this.o2);
			System.out.println();
		} catch (Exception e) {
			Assert.fail();
		}
	}

	@Test
	public void test_copyUtil03_copyProperties() {
		try {
			CopyUtil03.copyProperties(this.o1, this.o2);
			System.out.println("CopyUtil03的copyProperties方法单元测试");
			System.out.println("-------------源对象o1----------------");
			showObjectPropertyValue(this.o1);
			System.out.println("-------------目标对象o2----------------");
			showObjectPropertyValue(this.o2);
			System.out.println();
		} catch (Exception e) {
			Assert.fail();
		}
	}

	@Test
	public void test_copyUtil03_copyPropertiesExclude() {
		try {
			String[] excludsArray = new String[1];
			excludsArray[0] = "aac001";
			CopyUtil03.copyPropertiesExclude(this.o1, this.o2, excludsArray);
			System.out.println("CopyUtil03的copyPropertiesExclude方法单元测试");
			System.out.println("-------------源对象o1----------------");
			showObjectPropertyValue(this.o1);
			System.out.println("-------------目标对象o2----------------");
			showObjectPropertyValue(this.o2);
			System.out.println();
		} catch (Exception e) {
			Assert.fail();
		}
	}

	@Test
	public void test_copyUtil03_copyPropertiesInclude() {
		try {
			String[] includsArray = new String[2];
			includsArray[0] = "aac001";
			includsArray[1] = "ddd001";
			CopyUtil03.copyPropertiesInclude(this.o1, this.o2, includsArray);
			System.out.println("CopyUtil03的copyPropertiesInclude方法单元测试");
			System.out.println("-------------源对象o1----------------");
			showObjectPropertyValue(this.o1);
			System.out.println("-------------目标对象o2----------------");
			showObjectPropertyValue(this.o2);
		} catch (Exception e) {
			Assert.fail();
		}
	}

	private void showObjectPropertyValue(Object o) throws Exception {
		for (PropertyDescriptor property : Introspector.getBeanInfo(
				o.getClass(), Object.class).getPropertyDescriptors())
			System.out.println(property.getReadMethod()
					.invoke(o, new Object[0]));
	}
}

 单元测试输出结果:

CopyUtil01单元测试
-------------源对象o1----------------
00007
国产零零零零七
3.141592653589793
null
-------------目标对象o2----------------
00007
国产零零零零七
null
null
3.141592653589793

CopyUtil02单元测试
-------------源对象o1----------------
00007
国产零零零零七
3.141592653589793
null
-------------目标对象o2----------------
00007
国产零零零零七
null
null
3.141592653589793

CopyUtil03的copyProperties方法单元测试
-------------源对象o1----------------
00007
国产零零零零七
3.141592653589793
null
-------------目标对象o2----------------
00007
国产零零零零七
null
null
3.141592653589793

CopyUtil03的copyPropertiesExclude方法单元测试
-------------源对象o1----------------
00007
国产零零零零七
3.141592653589793
null
-------------目标对象o2----------------
null
国产零零零零七
null
null
3.141592653589793

CopyUtil03的copyPropertiesInclude方法单元测试
-------------源对象o1----------------
00007
国产零零零零七
3.141592653589793
null
-------------目标对象o2----------------
00007
null
null
null
3.141592653589793
    如上方式都是通过java的反射机制复制对象,不支持深度复制以及复制集合类型,但通用性会提高很多。java本身提供了对象复制的能力,在java.lang.Object类中有clone方法,该方法是一个protected方法,在子类需要重写此方法并声明为public类型,而且还需实现Cloneable接口才能提供对象复制的能力,clone()是一个native方法,native方法的效率一般来说都是远高于java中的非native方法,对性能比较关心的话应考虑这种方式。
 
二.利用Spring实现属性之间的复制
    spring内部自有实现方法,如果我们需要在外面采用spring的托管复制,需要修改spring的源码,将spring中的org.springframework.beans.CachedIntrospectionResults类的forClass、getPropertyDescriptor、getBeanInfo改为可见的后重新打包。然后将Spring中关于复制的代码提取出来,最后修改成代码如下:
/**
 * 利用spring实现bean之间属性复制
 * @param source
 * @param target
 */
@SuppressWarnings("unchecked")
public static void copyPropertiesBySpring(Object source, Object target) throws Exception {
	Class actualEditable = target.getClass();
	PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
	for (int i = 0; i < targetPds.length; i++) {
		PropertyDescriptor targetPd = targetPds[i];
		if (targetPd.getWriteMethod() != null) {
			PropertyDescriptor sourcePd = getPropertyDescriptor(source
					.getClass(), targetPd.getName());
			if (sourcePd != null && sourcePd.getReadMethod() != null) {
				try {
					Method readMethod = sourcePd.getReadMethod();
					if (!Modifier.isPublic(readMethod.getDeclaringClass()
							.getModifiers())) {
						readMethod.setAccessible(true);
					}
					Object value = readMethod.invoke(source, new Object[0]);
					if(value == null)
						continue;
					//集合类判空处理
					if(value instanceof Collection) {
//							Collection newValue = (Collection)value;
//							if(newValue.size() <= 0)
							continue;
					}
					Method writeMethod = targetPd.getWriteMethod();
					if (!Modifier.isPublic(writeMethod.getDeclaringClass()
							.getModifiers())) {
						writeMethod.setAccessible(true);
					}
					writeMethod.invoke(target, new Object[] { value });
				} catch (Throwable ex) {
				}
			}
		}
	}
}
	
/**
 * 获取指定类指定名称的属性描述符
 * @param clazz
 * @param propertyName
 * @return
 * @throws BeansException
 */
@SuppressWarnings("unchecked")
public static PropertyDescriptor getPropertyDescriptor(Class clazz,
		String propertyName) throws BeansException {
	CachedIntrospectionResults cr = CachedIntrospectionResults.forClass(clazz);
	return cr.getPropertyDescriptor(propertyName);
}

/**
 * 获取指定类得所有属性描述符
 * @param clazz
 * @return
 * @throws BeansException
 */
@SuppressWarnings("unchecked")
public static PropertyDescriptor[] getPropertyDescriptors(Class clazz) throws BeansException {
	CachedIntrospectionResults cr = CachedIntrospectionResults.forClass(clazz);
	return cr.getBeanInfo().getPropertyDescriptors();
}
 
三.利用apache commons-beanutils的开源实现
    BeanUtils.copyProperties(dst, src)。方法能够将源对象和目标对象中相同名称的属性值复制过去。注意的是参数前面的是目标对象,后面是源对象。使用该方法需要注意:不能将入口方法与源对象、目标对象之一放在同一源文件之内,否者将没有任何效果。
    PropertyUtils.copyProperties(dst, src)。功能与BeanUtils.copyProperties类似,只是在同属性名称的类型参数之间可以执行转换操作。
 
分享到:
评论
1 楼 qiuboboy 2014-05-14  
看下我实现的这种呢

http://bohr.me/2014/05/13/pojo-perperty-copy.html

相关推荐

    MyBatisDemo && JAVA把一个对象的全部属性复制到另一个相同的对象

    这篇博文“MyBatisDemo && JAVA把一个对象的全部属性复制到另一个相同的对象”探讨的是如何在Java编程中实现对象属性的深度复制。MyBatis是一个流行的Java持久层框架,它简化了数据库操作,而对象复制则是处理业务...

    java不同对象及集合的多次复制

    值复制,即对象属性值的复制,是保持数据一致性和简化代码的重要手段。本主题将深入探讨如何使用注解实现不同对象、相同对象以及集合与集合之间的多次复制,以避免繁琐的手动复制过程。 1. **对象复制的基本概念** ...

    java不同对象之间及集合的复制

    在Java编程中,对象之间的复制是一项常见的操作,特别是在数据传输、模型转换或者持久化存储等场景下。这里的“java不同对象之间及集合的复制”主要关注如何高效且便捷地完成对象及其集合的复制工作,避免繁琐的手动...

    java对象复制克隆

    标题中的“java对象复制克隆”主要涉及的是深拷贝,这是一种创建一个新对象的方式,新对象不仅复制了原对象的所有属性,还复制了嵌套的对象引用,使得修改复制后的对象不会影响到原始对象。 **浅拷贝**:在浅拷贝中...

    Java对象的复制克隆

    Java中的对象复制与克隆是程序开发中常见的需求,主要用于创建一个对象的副本,而不会影响原始对象的状态。这里主要讨论两种类型的对象拷贝:浅拷贝和深拷贝。 浅拷贝,也称为表面拷贝,是创建一个新的对象,然后将...

    java 对象克隆

    总结,Java中的对象克隆是一项重要的功能,用于复制和独立化对象。通过实现`Cloneable`接口和覆盖`clone()`方法,我们可以创建浅克隆对象。对于更复杂的场景,可以自定义克隆逻辑或利用序列化来实现深克隆。理解并...

    对象属性值的复制工具类

    对象属性值的复制工具类 1.全复制 2.部分复制 3.部分不复制

    两个对象属性值的拷贝和文件的拷贝

    实现了两个对象之间属性值的拷贝,只要具有相同的属性名就可以拷贝,还有两个file对象的拷贝,实现文件的复制功能

    java List 深度复制方法

    但对于可变对象(如自定义类实例),我们需要通过序列化和反序列化,或者手动创建新对象并设置属性值来实现深复制。 以下是一个简单的深复制示例,使用了Java的序列化机制: ```java import java.io.*; public ...

    编程语言java对象复制.pdf

    在标题“编程语言java对象复制.pdf”和描述“编程语言java对象复制.pdf”中,明确指出了文档的主题是关于Java编程语言中对象复制的技术知识。在给出的内容部分中,通过具体的Java代码示例,讨论了在Java中实现对象...

    java对象复制.pdf

    Java对象复制是一个重要的概念,它涉及到Java中对象的深拷贝和浅拷贝。当我们需要一个与原有对象具有相同属性的新对象,但不希望修改新对象会影响原对象时,就需要进行对象复制。Java提供了多种复制对象的方式,其中...

    java对象复制[参考].pdf

    Java对象复制主要分为浅复制(Shallow Copy)和深复制(Deep Copy)。本文将深入探讨Java对象复制,特别是通过`clone()`方法实现的复制。 首先,我们来理解什么是对象复制。对象复制是指创建一个新对象,这个新对象...

    JAVA_对象克隆

    这个过程在需要复制对象的所有属性而不创建新类型实例时非常有用。本文将深入探讨Java中的对象克隆,包括其原理、实现方式以及注意事项。 一、对象克隆的原理 在Java中,对象克隆可以通过实现`Cloneable`接口并覆盖...

    java类复制一个持久化对象

    下面是对给定代码片段的详细分析,该代码展示了如何使用反射来复制一个Java对象: ```java public static Object copy(Object object) throws Exception { Class&lt;?&gt; classType = object.getClass(); Object ...

    Java copy对象的工具类

    Java CopyUtil工具类,可以进行对象的深copy,比如:对象里面包含对象,对象里面包含Map,List,Set...等复杂类型的属性都可以copy,copy后的对象与原有对象没有联系,即改变原有对象内容,不会改变copy后的对象里面的...

    java对象复制

    Java对象的复制主要有两种方式:浅复制(Shallow Copy)和深复制(Deep Copy)。标题中的"java对象复制"主要涉及到Java中对象复制的基本概念、实现方法以及相关的注意事项。 首先,Java中的对象复制问题源于其默认...

    Java对象的复制三种方式(小结)

    "Java对象的复制三种方式" Java对象的复制是Java编程中的一种常见操作,主要是将一个对象的值复制到另一个对象中,使得两个对象独立,但具有相同的初始值。在实际编程过程中,我们常常需要复制对象,以便于对象之间...

    Java程序_复制文件.jar

    在这个程序中,`java.io.File`类被用来创建和操作文件对象,而`java.io.FileInputStream`和`java.io.FileOutputStream`则用于读取和写入文件内容,实现文件的复制。 文件复制在Java中通常通过读取源文件并写入目标...

    Java中对象的深复制和浅复制详解.doc

    如果对象的属性不包含对其他对象的引用,或者你希望修改副本不会影响原始对象,那么浅复制可能是足够的。然而,如果你的对象包含复杂的嵌套结构,或者需要保持原始和副本之间的独立性,那么深复制是必要的。正确理解...

Global site tag (gtag.js) - Google Analytics