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)


相关推荐

  • 5 . 4 . 3 架构

    5 . 4 . 3 架构

  • int使用规则_point是什么意思

    int使用规则_point是什么意思先说结论吧,方便快速查询验证。总结区别int类型大小为8字节int8类型大小为1字节int16类型大小为2字节int32类型大小为4字节int64类型大小为8字节go语言中的int的大小是和操作系统位数相关的,如果是32位操作系统,int类型的大小就是4字节;如果是64位操作系统,int类型的大小就是8个字节取值范围int8:-128~127int16:-32768~32767int32:-2147483648~214

  • 【转载】D3D深度测试和Alpha混合

    【转载】D3D深度测试和Alpha混合

  • 前端面试ajax考点汇总_javascript常见面试题

    前端面试ajax考点汇总_javascript常见面试题前端面试题总结(四)ajax篇1、什么是AJAX,为什么要使用Ajax(请谈一下你对Ajax的认识)什么是ajax:AJAX是“AsynchronousJavaScriptandXML”的缩写。他是指一种创建交互式网页应用的网页开发技术。Ajax包含下列技术:基于web标准(standards-basedpresentation)XH…

  • 运维面试官喜欢问的问题是_运维是什么意思

    运维面试官喜欢问的问题是_运维是什么意思你最大的缺点是什么?行为问题(behaviouralquestion),这类问题目的是看性格是否合适公司文化。主要考察:①你是否真心想做这个工作;②你性格与企业文化是否相符。所有答案都应该围绕这两点组织,即每个经历都应回归到你通过这个经历学到什么该职位所需关键技巧,这些经历为何让你想做这个工作,和该经历体现出你什么样的个人风格。你最大的缺点是什么:①避免避重就轻,谈一个算不得缺点的缺点,这…

  • 数组操作方法(包括es6数组的操作方法)[通俗易懂]

    数组操作方法(包括es6数组的操作方法)[通俗易懂]//(1)push()//向数组最里面推一个或多个数据vararr=[“色”,”等”,”烟”,”雨”];arr.push(“而”,’我’,”在”);console.log(arr);//(2)unshift()//在数组的开头添加一个或多个数据vararr=[“色”,”等…

发表回复

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

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