BeanUtils工具类中的copyProperties方法使用「建议收藏」

BeanUtils工具类中的copyProperties方法使用「建议收藏」文章目录1、两个包下的BeanUtils.copyProperties对比2、BeanUtils.copyProperties的深浅拷贝问题2.1、浅拷贝和深拷贝2.2、BeanUtils.copyProperties深浅拷贝问题1、两个包下的BeanUtils.copyProperties对比BeanUtils是开发中常用到的工具类,而获取这一工具类主要是通过导入org.springframework.beans.BeanUtils或者org.apache.commons.beanutils.Bean

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

1、两个包下的BeanUtils.copyProperties对比

BeanUtils是开发中常用到的工具类,而获取这一工具类主要是通过导入org.springframework.beans.BeanUtils或者org.apache.commons.beanutils.BeanUtils包来获取,但是不同的包中BeanUtils的方法使用是不一样的,接下来就对这两个包中的copyProperties方法进行对比。

先来看一下这两个包中的copyProperties方法的定义:

//org.springframework.beans.BeanUtils
public static void copyProperties(Object source, Object target){ 
   ....}

//org.apache.commons.beanutils.BeanUtils
public static void copyProperties(Object dest,Object orig){ 
   ....}

由定义可知,在org.springframework.beans.BeanUtils包下的copyProperties第一个参数是被copy的对象,而org.apache.commons.beanutils.BeanUtils中是第二个参数,所以使用时不要弄混。

1)接下来定义两个实体类Student和Teacher,用来模拟目标对象(target/dest)中包含被copy的对象(source/orig)的所有字段时

@Data
public class Student { 
   
	private String id;
	private String name;
	private String age;
    
    public Student(String id, String name, String age) { 
   
		this.id = id;
		this.name = name;
		this.age = age;
	}
}

@Data
public class Teacher { 
   
	private String id;
	private String name;
	private String age;
	private String sex;   //多出来的参数

    public Teacher() { 
   }
	public Teacher(String id, String name, String age, String sex) { 
   
		this.id = id;
		this.name = name;
		this.age = age;
		this.sex = sex;
	}	
}

先使用org.springframework.beans.BeanUtils下的copyProperties来进行测试,执行代码如下:

import org.springframework.beans.BeanUtils;

public static void main(String[] args) throws Exception { 
   
	Student student = new Student(UUID.randomUUID().toString(), "zhangsan", "19");
	Teacher teacher = new Teacher();
	System.out.println(student.toString());
	BeanUtils.copyProperties(student,teacher);
	System.out.println(teacher.toString());
}
执行结果如下:
	Student(id=00c47e77-785d-4939-89db-e757979050ec, name=zhangsan, age=19)
	Teacher(id=00c47e77-785d-4939-89db-e757979050ec, name=zhangsan, age=19, sex=null)

当将引入的包改为org.apache.commons.beanutils.BeanUtils时,将上述中的执行代码进行如下修改:

BeanUtils.copyProperties(teacher,student); //因为apache包下被copy的参数在第二个位置
执行结果如下:
	Student(id=900d0b93-1913-4022-b86b-127682cd9f5c, name=zhangsan, age=19)
	Teacher(id=00c47e77-785d-4939-89db-e757979050ec, name=zhangsan, age=19, sex=null)

小结:当目标对象(target/dest)中包含被copy的对象(source/orig)的所有字段时,两种包下的copyProperties方法均可以执行成功。

2)对上述中说到的实体类进行修改,即目标对象(target/dest)中不包含被copy的对象(source/orig)的所有字段时,修改后的内容如下:

@Data
public class Student { 
   
	private String id;
	private String name;
	private String age;
    
    public Student(String id, String name, String age) { 
   
		this.id = id;
		this.name = name;
		this.age = age;
	}
}

@Data
public class Teacher { 
   
	private String id;
	private String name;
    
	public Teacher() { 
   }
	public Teacher(String id, String name) { 
   
		this.id = id;
		this.name = name;
	}	
}

执行代码与1)中的一样这里就不写了,先使用org.apache.commons.beanutils.BeanUtils中的copyProperties方法,执行结果如下:

    Student(id=6f6711ef-fa2f-420d-b0b3-b76998356533, name=zhangsan, age=19)

    Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/collections/FastHashMap
        at org.apache.commons.beanutils.PropertyUtilsBean.getPropertyDescriptor(PropertyUtilsBean.java:964)
        at org.apache.commons.beanutils.PropertyUtilsBean.isWriteable(PropertyUtilsBean.java:1479)
        at org.apache.commons.beanutils.BeanUtilsBean.copyProperties(BeanUtilsBean.java:280)
        at org.apache.commons.beanutils.BeanUtils.copyProperties(BeanUtils.java:135)
        at com.learn.controller.BeanController.main(BeanController.java:39)
    Caused by: java.lang.ClassNotFoundException: org.apache.commons.collections.FastHashMap
        at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        ... 5 more

接下来使用org.springframework.beans.BeanUtils下的copyProperties方法,执行结果如下:

    Student(id=87665c46-9a6f-4936-9c9d-1513e29f2bca, name=zhangsan, age=19)
    Teacher(id=87665c46-9a6f-4936-9c9d-1513e29f2bca, name=zhangsan)

小结:目标对象(target/dest)中不包含被copy的对象(source/orig)的所有字段时,应选用org.springframework.beans.BeanUtils下的copyProperties方法

3)基于2)中的实体类来看下另外一种情况,修改下执行代码,实体类不变:

	public static void main(String[] args) throws Exception { 
   
		Student student = new Student(UUID.randomUUID().toString(), "zhangsan", "19");
		Teacher teacher = new Teacher("12334","lisi");
		System.out.println(student.toString());
		BeanUtils.copyProperties(student,teacher);
		System.out.println(teacher.toString());
	}

先使用org.apache.commons.beanutils.BeanUtils中的copyProperties方法,执行结果如下:

Student(id=16bf375a-5925-4411-8bdf-158b3373d261, name=zhangsan, age=19)
Teacher(id=12334, name=zhangsan)
Student(id=12334, name=zhangsan, age=19)

接下来使用org.springframework.beans.BeanUtils下的copyProperties方法,执行结果如下:

Student(id=2df2fba9-22a2-4cb6-86d7-3d5b47475114, name=zhangsan, age=19)
Teacher(id=12334, name=zhangsan)
Student(id=12334, name=zhangsan, age=19)

小结:目标对象(target/dest)中包含被copy的对象(source/orig)的所有字段时,两个包下的copy方法都可以,而且目标对象(target/dest)中多于的对象的值不会被覆盖掉。

总结:

​ 1、org.apache.commons.beanutils.BeanUtils和org.springframework.beans.BeanUtils两个包中的copyProperties方法目标对象和源对象参数的位置是相反,使用时需要注意。

​ 2、使用org.apache.commons.beanutils.BeanUtils进行copy对象时,被copy的对象(source/orig)中包含的字段目标对象(target/dest)必须包含,可以有其他的多于字段,类型可以不相同,但字段名称必须一致;org.springframework.beans.BeanUtils中的没有这个限制。

2、BeanUtils.copyProperties的深浅拷贝问题

2.1、浅拷贝和深拷贝

先来说一下什么是浅拷贝,深拷贝;两者最主要的区别就在于是否是复制了对象的真实实体还是说只是使用了一个指针,两者指向的是内存中的同一个对象。

浅拷贝(shallowCopy)只是增加了一个指针指向已存在的内存地址;

深拷贝(deepCopy)是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存;同时如果一个类中包含有引用类型变量,则该类拷贝以后引用类型也会被拷贝。

参考博文:
1、深拷贝和浅拷贝的区别
2、java中clone方法的理解(深拷贝、浅拷贝)
3、System.arraycopy()使用原理解析,坑点之:深拷贝和浅拷贝

2.2、BeanUtils.copyProperties深浅拷贝问题

BeanUtils.copyProperties使用起来虽然方便,但是它其实只是浅拷贝,所以类中都是单一的属性,像咱们上边介绍的,可以直接用;如果类中包含有其他的子类就需要考虑下拷贝后目标对象(target/dest)中包含被copy的对象(source/orig)中的子类是否有可能被修改,如果有可能被修改就不能直接使用。

新增加一个实体类Life,接下来我们将上述中的代码进行一个改造:

@Data
public class Life { 
   
	private String life;

	public Life(String life) { 
   
		this.life = life;
	}
}
@Data
public class Teacher { 
   
	private String id;
	private String name;
	private Life life;

	public Teacher(String id, String name) { 
   
		this.id = id;
		this.name = name;
	}
	public Teacher() { 
   }
}

@Data
public class Student { 
   
	private String id;
	private String name;
	private String age;
	private Life life;
    
    public Student(String id, String name, String age) { 
   
		this.id = id;
		this.name = name;
		this.age = age;
	}
}
import org.springframework.beans.BeanUtils;
public class BeanController { 
   

	public static void main(String[] args) throws Exception { 
   
		Student student = new Student(UUID.randomUUID().toString(), "zhangsan", "19");
		Life life=new Life("young");
		student.setLife(life);
		Teacher teacher = new Teacher();
		System.out.println(student.toString());
		BeanUtils.copyProperties(student,teacher);
		teacher.getLife().setLife("old");
		System.out.println(student.toString());
	}
}
执行结果如下:
	Student(id=988cac88-638c-4e52-8421-db39590ed32c, name=zhangsan, age=19, life=Life(life=young))
Student(id=988cac88-638c-4e52-8421-db39590ed32c, name=zhangsan, age=19, life=Life(life=old))

正常情况下,Student中的life值应该为young,但是student拷贝给teacher以后,随着teacher中life修改,student中的life也被修改,说明teacher和student两个对象中的life子对象为内存中的同一个life对象,所以BeanUtils.copyProperties属于浅拷贝。

参考博文:BeanUtils.copyProperties深拷贝的使用

3、深拷贝的方法

这里介绍一种深拷贝的方法,先将集合转化为字节数组输出流,然后在读取,这样就可以实现深度拷贝,代码如下:

	public <T> List<T> deepCopy(List<T> src) throws IOException, ClassNotFoundException { 
     
		// 将该对象序列化成流,因为写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。所以利用这个特性可以实现对象的深拷贝
	    ByteArrayOutputStream byteOut = new ByteArrayOutputStream();  
	    ObjectOutputStream out = new ObjectOutputStream(byteOut);  
	    out.writeObject(src);  
	  
	    ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());  
	    ObjectInputStream in = new ObjectInputStream(byteIn);  
	    @SuppressWarnings("unchecked")  
	    List<T> dest = (List<T>) in.readObject();  
	    return dest;  
	}  

参考博文:序列化(Serialization)实现深拷贝

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/186226.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • SQL报错注入_报错注入原理

    SQL报错注入_报错注入原理目录1报错注入概述2常用的报错注入命令2.2groupby重复键冲突(count()+floor()+rand()+groupby组合)2.2.1groupby重复键冲突的原理及bug演示2.2.2补充:sql语句解析过程2.3XPATH报错2.3.1extractvalue()函数2.3.2updatexml()函数2.4测试失败的命令3报错注入案例3.1操作环境3.2获取敏感信息3.2.1获取数据库名3.2.2获取表名3.2.3获取字段名3.2.4获取字段内

  • kettle工具 学习

    kettle工具 学习背景:项目需要从客户的数据库迁移一批人口数据,大约240w条。所以我们需要一款工具帮助我们实现数据快速搬运,数据过滤,以得到符合我们使用的安全数据。

    2022年10月10日
  • Windows Phone 奇怪现象之ListBox在WP8能载入数据在WP7.x不能

    Windows Phone 奇怪现象之ListBox在WP8能载入数据在WP7.x不能

  • Redis集群主从复制(一主两从)搭建配置教程【Windows环境】

    如何学会在合适的场景使用合适的技术方案,这值得思考。由于本地环境的使用,所以搭建一个本地的Redis集群,本篇讲解Redis主从复制集群的搭建,使用的平台是Windows,搭建的思路和Linux上基本一致! (精读阅读本篇可能花费您15分钟,略读需5分钟左右)Redis主从复制简单介绍为了使得集群在一部分节点下线或者无法与集群的大多数节点进行通讯的情况下, 仍然可以正常运…

  • 课程表app源码_课程表模板excel

    课程表app源码_课程表模板excel快乐的时光过得特别快,很快各位学生党就要迎来新学期了。课程表对学生的意义不言而喻,特别是对作息自理的大学生来说,没课程表不知道要不要上课丝毫不奇怪,这时在手机上装一个课程表App就省事多了。课程表App为数不少,但你听说过能够撩学妹泡妞的课程表App吗?今天介绍的这款课程格子,就有这么个功能。软件名称:课程格子软件版本:3.00官方版软件大小:5.98MB软件授权:免费适用平台:Android实…

  • vue父组件操作子组件的方法_vue父组件获取子组件数据

    vue父组件操作子组件的方法_vue父组件获取子组件数据父组件和子组件我们经常分不清什么是父组件,什么是子组件。现在来简单总结下:我们将某段代码封装成一个组件,而这个组件又在另一个组件中引入,而引入该封装的组件的文件叫做父组件,被引入的组件叫做子组件。具

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号