java复制对象 commons-beanutils. BeanUtils

关于bean复制,如果属性较少,建议直接写个方法完成get/set即可。如果属性较多,可以自己采用反射实现一个满足自己需要的工具类,或者使用spring的那个beanutils类,不建议使用commons-beanutils包中的那个BeanUtils类,刚看了下,这个类对于内部静态类的对象复制也会出现问题,检验太复杂了,常会出现一些诡异的问题。毕竟我们bean复制一般就是简单的属性copy而已。

而且,由于这些BeanUtils类都是采用反射机制实现的,对程序的效率也会有影响。因此,慎用BeanUtils.copyProperties!!!以下仅作为例子

 

apache提供了一套开源的api BeanUtils组件,方便对javabean的操作。我们可以使用该组件完成对象属性的拷贝和对象的整体拷贝等功能。该组件的使用很广泛,例如对象使用泛型时,可用于给泛型对象的属性赋值。下面介绍BeanUtils组件的基本用法。

我们经常会从各种配置文件中读取相应的数据,从配置文件中读取到的数据都是String,显然程序中不仅仅有String一种数据类型,比如:基本数据类型(int、double、char、float等),还有自定义数据类型(引用数据类型)这时BeanUtils组件就排上了用武之地.

 

项目中引入commons-beanutils.jar和commons-logging.jar这两个jar包,zapom文件中添加如下的配置即可。


必须满足 三个条件 :无参数构造器(不创建有参数构造器,即会有系统默认的无参构造器)、成员,public get/set属性

public class Persion {
      String name;
      int age;
      Date birthday;
      //此处省略set get方法,BeanUtils基于set get方法 因此一定要有 
      //另外set get方法一定遵守 setName getName 赋值是根据此类方法赋值和name命名无关系
}
涉及的方法	
   void   BeanUtils.copyProperty(Object bean, String name, Object value) bean是指你将要设置的对象,name指的是将要设置的属性(写成”属性名”),value 要设置的值
   void   BeanUtils.setProperty(Object bean, String name, Object value) bean是指你将要设置的对象,name指的是将要设置的属性(写成”属性名”), value 要设置的值
   String BeanUtils.getProperty或getSimpleProperty(Object bean, String name) 获取对应对象的属性值 返回值是string类型
   void   BeanUtils.copyProperties(Object dest, Object orig)实现对象的属性值浅拷贝,复制后的2个Bean的同一个属性可能拥有同一个对象的ref,这个在使用时要小心,特别是对于属性为自定义类的情况
   void   BeanUtils.populate(Object bean,Map<String,? extends Object> properties)其中Map中的key必须与目标对象中的属性名相同,否则不能实现拷贝。
   Map    BeanUtils.describe(Object bean) 获取描述,key是属性 value是值 还有class 相关信息
   void    ConvertUtils.register(Converter converter , ..),当需要将String数据转换成引用数据类型(自定义数据类型时),需要使用此方法实现转换。
 
 

 Simple——简单类型,如Stirng、Int……   

 Indexed——索引类型,如数组、arrayList……   

 Maped——这个不用说也该知道,就是指Map啦,比如HashMap……   

 
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.ObjectUtils;
public static void main(String[] args) throws Exception{
		Persion persion = new Persion();
		BeanUtils.copyProperty( persion, "name", "李四" );// 给对象的属性赋值
		BeanUtils.setProperty( persion, "age", 18 );// 给对象的属性赋值,如无该属性亦不会报错 如果值为"你" 则age值为默认值
		System.err.println( BeanUtils.getProperty( persion, "name" ) + " : " +BeanUtils.getProperty( persion, "age" ) );

		Persion destPersion = new Persion();
		BeanUtils.copyProperties( destPersion, persion );// 将originBean的属性  赋值到destBean,如果两者属性名称不一致那么不能赋值成功
		System.out.println( destPersion.toString() );
				
		// 注意 map的key要和属性值一致  否则赋值不成功
		Map<String, Object> valuehMap = new HashMap<>();
		valuehMap.put( "name", "张三" );
		valuehMap.put( "age", 18 );
		Persion populatePersion = new Persion();
		BeanUtils.populate( populatePersion, valuehMap );// populate 移民于; 落户于
		Map<String, Object> describe = BeanUtils.describe( populatePersion );
		Set<Entry<String, Object>> entrySet = describe.entrySet();
		for (Iterator<Entry<String, Object>> iterator = entrySet.iterator(); iterator.hasNext();) { 
			Entry<String, Object> entry = iterator.next();
			System.err.println( entry.getKey() + "-------!!" + ObjectUtils.toString( entry.getValue() ) );
		};
	}
类中新增属性
	String name;
	int age;
	Date birthday; //字符创转成date类型
涉及方法   ConvertUtils.register(Converter converter, 目标类型.class);
Person2 person = new Person2();
BeanUtils.copyProperty(person, "name", "jack");
BeanUtils.setProperty(person, "age", "18");
String birthday = "2009-09-09";
// 注册日期类型转换器(使用组件提供的转换器工具类) 不灵活
ConvertUtils.register(new DateLocaleConverter(), Date.class);
BeanUtils.copyProperty(person, "birthday", birthday);
System.out.println( person.toString() );

 

 或使用自定义转换器    ConvertUtils.register(new Converter() {
			@Override
			public Object convert(Class class1, Object obj) {//type:目前需要转换的数据类型 value:目前参数的值
				System.out.println( obj );
				if (class1!=Date.class) {
					return null;
				}
				
				if (obj==null||"".equals( obj.toString().trim() )) {
					return null;
				}
				
				try {
					return new SimpleDateFormat( "yyyy-MM-dd" ).parse( obj.toString() );
				} catch (ParseException e) {
					e.printStackTrace();
					throw new RuntimeException();
				}
			}
		},Date.class);//Date.class表示要转换的成引用类型,Date类型不是基本数据类型,所以需要一个转换器进行相应的转换
		BeanUtils.copyProperty(person, "birthday", birthday);

另外还有方法: 
     

static String[]	getArrayProperty(Object bean, String name)	   返回指定属性的值,作为字符串数组返回
static String	getIndexedProperty(Object bean, String name)	获取指定索引位置对象作为字符串返回
static String	getIndexedProperty(Object bean, String name, int index)	获取指定索引位置对象作为字符串返回
static String	getMappedProperty(Object bean, String name)	获得Map属性值作为字符串返回
static String	getMappedProperty(Object bean, String name, String key)	获得Map属性中指定键的值作为字符串返回
static String	getNestedProperty(Object bean, String name)	获得嵌套属性作为字符串返回
 

BeanUtils和PropertyUtils

       这两个类几乎有一摸一样的功能,唯一的区别是:BeanUtils在对Bean赋值是会进行类型转化。举例来说也就是在copyProperty时只要属性名相同,就算类型不同,BeanUtils也可以进行copy,只是相应的属性值为默认值;而PropertyBean则可能会报错!!

       针对上面的例子,新建一个Person2的类,其中代码与Company一样,只是将otherinfo从String[]改为String。

      Person  p = new   Person ();

      Person2  p2 = new Person2();

     BeanUtils.copyProperties(p2,p);

//    PropertyUtils.copyProperties(p2,p); 这句会报错!! argument type mismatch

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

    当然2个Bean之间的同名属性的类型必须是可以转化的,否则用BeanUtils一样会报错。

       若实现了org.apache.commons.beanutils.Converter接口则可以自定义类型之间的转化。

由于不做类型转化,用PropertyUtils在速度上会有很大提高!

此外,不作类型转化还有一个好处,如下面的代码:

//    ArrayList a1 = BeanUtils.getProperty(c,"name"); //BeanUtils返回的是String

      System.out.println("--" + BeanUtils.getProperty(c,"name"));     //取出后直接被转为String

      String a = (String)PropertyUtils.getProperty(c,"name");//PropertyUtils返回的是Object

用BeanUtils无法返回一个对象(除非自己写一个Converter),它会自动进行类型转化,然后返回String。对于想返回java类或自定义类的话,还是请使用PropertyUtils

 

 

业务系统中经常需要两个对象进行属性的拷贝,不能否认逐个的对象拷贝是最快速最安全的做法,但是当数据对象的属性字段数量超过程序员的容忍的程度,代码因此变得臃肿不堪,使用一些方便的对象拷贝工具类将是很好的选择。

性能对比: BeanCopier > PropertyUtils > BeanUtils. 其中BeanCopier的性能高出另外两个100数量级。

目前流行的较为公用认可的工具类:

Apache的两个版本:(反射机制)
org.apache.commons.beanutils.PropertyUtils.copyProperties(Object dest, Object orig)
org.apache.commons.beanutils.BeanUtils.copyProperties(Object dest, Object orig)
Spring版本:(反射机制)
org.springframework.beans.BeanUtils.copyProperties(Object source, Object target, Class editable, String[] ignoreProperties)
cglib版本:(使用动态代理,效率高)

net.sf.cglib.beans.BeanCopier.copy(Object paramObject1, Object paramObject2, Converter paramConverter)

BeanCopier copier= BeanCopier.create(person1.getClass(), person.getClass(), false);

copier.copy(person1, person, null);

 

 

BeanCopier.copy 参考 http://czj4451.iteye.com/blog/1998750

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值