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)实现深拷贝

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Linux系统安装Cache数据库配置环境

    Linux系统安装Cache数据库配置环境1 Cach 介绍 nbsp 官网 https www intersystems com 开发者社区 https community intersystems com nbsp nbsp gt gt nbsp download nbsp Cach 安装指南 https docs intersystems com latest csp docbook DocBook UI Page cls KEY G

    2025年11月8日
    3
  • 【转载】TCP和TCP/IP的区别

    【转载】TCP和TCP/IP的区别

    2021年11月18日
    88
  • goland 2021.2.3 服务器激活(在线激活)

    goland 2021.2.3 服务器激活(在线激活),https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月14日
    365
  • 背包九讲问题——超详细

    背包九讲问题——超详细Acwing背包题库一.01背包问题问题描述有N件物品和一个容量是VV的背包。每件物品只能使用一次。第i件物品的体积是vi,价值是wi。求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。输出最大价值。输入格式第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。接下来有N行,每行两个整数vi,wi,用空格隔开,分别表示第i件物品的体积和价值。输出格式输出一个整数,表示最大价值。数据范围0<N,V≤100

    2022年6月28日
    28
  • 五个最佳FTP客户端工具「建议收藏」

    五个最佳FTP客户端工具「建议收藏」概述无论你是做网站工作,还是运行一个家庭FTP服务器,或者你只是喜欢高速下载,一个稳定且功能齐全的FTP客户端工具都可以节省你大量时间和生命,现在有大量的免费或者收费的FTP客户端软件供大家选择,这里总结了五个流行的FTP客户端软件。FileZilla(所有平台)FileZillaFileZilla是一个免费开源的适合Windows、Mac和Linux的FTP客户端软件,因为其实免费跨平台和易用性,因此它是很多FTP用户的最初选择,FileZilla下载速度非常快,功能齐全,如果你是Wind

    2022年8月30日
    2
  • 公司拿到了量化交易模型, 交易员和策略师就可滚蛋了?[通俗易懂]

    公司拿到了量化交易模型, 交易员和策略师就可滚蛋了?[通俗易懂]作者:天启大烁哥源自:天启量投(ID:QDLG001)在知乎上看到了一个很有趣的问题。在这个问题下面,提问者留了一些自己的看法:有种感觉,资本一直试图用电脑代替人,把人的工作用电脑替代,这样资本就可以拿走人的技术,拿走技术的费用是低廉的,这么做貌似很划算。炒了两年期货了,琢磨用程序来替代自己,但是发现很困难,我是搞电脑的没有技术障碍,算法不难,难就难在我自己的不确定…

    2022年6月26日
    25

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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