开头聊几句

1、网上很多的技术文章和资料是有问题的,要学会辨证的看待,不能随便就拿来用,起码要自己验证一下

2、关注当下,关注此刻,如果你真正阅读本篇文章,请花几分钟时间的注意力阅读,相信你会有收获的

3、文中代码没有使用图片展示,可能存在阅读排版错乱问题,请见谅,因为可能考虑到有其他伙伴需要拷贝代码,这样比较方便

Java常用属性拷贝工具类使用总结

对项目中经常使用的属性拷贝工具类进行总结:

org.apache.commons.beanutils.BeanUtils

org.apache.commons.beanutils.PropertyUtils

org.springframework.beans.BeanUtils

本文使用的工具类对应的版本:

commons-beanutils:1.9.4

spring-beans:5.0.7.RELEASE

字段和属性

首先明确下在Java中字段和属性的区别。

属性是不是类里最上边的那些全局变量吗?比如:

public class UserTest{

private String userName;

private String password;

public String getUserName() {

return userName;

}

public void setUserName(String userName) {

this.userName = userName;

}

public String getPassword() {

return password;

}

public void setPassword(String password) {

this.password = password;

}

public String getHello() {

return "hello";

}

public void setHello(String str) {

}

}

上面 private String userName;private String password;。准确的来说它们应该称为:字段,而不是本次要讲的属性。

下面简述一下:什么是Java中的属性?

Java中的属性(property),通常可以理解为get和set方法,而字段(field),通常叫做“类成员”,或“类成员变量”,有时也叫“域”,理解为“数据成员”,用来承载数据的。

直白点就是Java中的属性是指:设置和读取字段的方法,也就是平常见到的set和get方法。只要是set和get开头的方法在Java里都认为它是属性(请注意这句话,等下后边会写代码做验证)

属性名称:就是set和get方法名 去掉"set"和"get"后的内容

比如:

public void setUserName(String userName) {

this.userName = userName;

}

它的属性名称是:userName(也就是方法名称”setUserName”去掉“set”)

当然 setUserName和 getUserName 方法是指同一个属性 UserName,

这里再次提醒:字段和属性不是同一个东西。

代码验证属性

上面代码中还有一个 getHello  和 setHello  , JDK 中有个API Introspector

获取的是java.beans.BeanInfo 类。这个类可以通过

java.beans.BeanInfo#getPropertyDescriptors : 获取java bean 所有的属性。

public static void main(String[] args) throws IntrospectionException {

BeanInfo beanInfo = Introspector.getBeanInfo(UserTest.class);

// 得到类中的所有的属性描述器

PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();

System.out.println("属性的个数:" + pds.length);

for (PropertyDescriptor pd : pds) {

System.out.println("属性:" + pd.getName());

}

}

结果:

属性的个数:4

属性:class

属性:hello

属性:password

属性:userName

上面多了一个 class ,原因很简单,因为Object类是所有类的父类,Object类里有个方法叫 getClass();

所以这也验证了咱们刚才说的: “只要是set或者get开头的方法都叫属性”

使用说明

default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。

public : 对所有类可见。使用对象:类、接口、变量、方法

private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)

protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)

org.springframework.beans.BeanUtils#copyProperties

1.基本类型和包装类型会自动转换, 方法名称相同,返回值类型和参数类型不同,不进行复制,也不报错_

2.支持指定忽略某些属性不复制

3、支持类的修饰符 default 、 public

org.apache.commons.beanutils.PropertyUtils#copyProperties

1.基本类型和包装类型会自动转换

2.方法名称相同,返回值类型和参数类型不同,复制失败,会报错,如下:

_argument type mismatch - had objects of type "java.lang.Double" but expected signature "java.lang.String"

3.只支持类的修饰符 public,如果是default 则直接不会进行转换(注意内部类复制也要加public)

org.apache.commons.beanutils.BeanUtils#_copyProperties

1.基本类型和包装类型会自动转换

2.方法名称相同,返回值类型和_ _参数类型不同,不复制,不报错

3.只支持类的修饰符 public,如果是default 则直接不会进行转换(注意内部类复制也要加public)

tips: Spring和apache的_copyProperties_属性的方法源和目的参数的位置正好相反,所以导包和调用的时候都要注意一下。

// Apache

public static void

copyProperties(final Object dest, final Object orig)

// Spring

public static void

copyProperties(Object source, Object target)

摘要总结:Spring是在次数增多的情况下,性能较好,在数据较少的时候,性能比PropertyUtils的性能差一些。PropertyUtils的性能相对稳定,表现是呈现线性增长的趋势。而Apache的BeanUtil的性能最差,无论是单次Copy还是大数量的多次Copy性能都不是很好。

根据上面的具体的分析还是使用 :org.springframework.beans.BeanUtils#copyProperties

原因:

1.这个方法在复制的时候不会因为属性的不同而报错,影响代码执行

2.性能方面也相对较好

其他Apache的两个,

1、org.apache.commons.beanutils.PropertyUtils#copyProperties 复制会直接报错

2、org.apache.commons.beanutils.BeanUtils#copyProperties 性能相对较差

原理探索

核心本质都是使用反射实现。具体的实现代码稍有不同。

Spring#BeanUtils

private static void copyProperties(Object source, Object target, @Nullable Class> editable,

@Nullable String... ignoreProperties) throws BeansException {

Assert.notNull(source, "Source must not be null");

Assert.notNull(target, "Target must not be null");

Class> actualEditable = target.getClass();

if (editable != null) {

if (!editable.isInstance(target)) {

throw new IllegalArgumentException("Target class [" + target.getClass().getName() +

"] not assignable to Editable class [" + editable.getName() + "]");

}

actualEditable = editable;

}

PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);

List ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null);

for (PropertyDescriptor targetPd : targetPds) {

Method writeMethod = targetPd.getWriteMethod();

if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {

PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());

if (sourcePd != null) {

Method readMethod = sourcePd.getReadMethod();

if (readMethod != null &&

ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {

try {

if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {

readMethod.setAccessible(true);

}

Object value = readMethod.invoke(source);

if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {

writeMethod.setAccessible(true);

}

writeMethod.invoke(target, value);

}

catch (Throwable ex) {

throw new FatalBeanException(

"Could not copy property '" + targetPd.getName() + "' from source to target", ex);

}

}

}

}

}

}

1、获取 目标对象 所有的属性 targetPds

PropertyDescriptor_[] _targetPds = getPropertyDescriptors(actualEditable);

2、循环 targetPds ,并在源对象取出对应的属性

PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName_())_;

3、r如果不是修饰不是public,暴力反射 ,然后使用对属性进行设值

setAccessible_(true);// 暴力反射

writeMethod.invoke(target, value)_;

### apache.commons#BeanUtils

org.apache.commons.beanutils.BeanUtilsBean#copyProperties

简单截取核心代码:

// org.apache.commons.beanutils.BeanUtilsBean#copyProperties

final PropertyDescriptor[] origDescriptors =

getPropertyUtils().getPropertyDescriptors(orig);

for (PropertyDescriptor origDescriptor : origDescriptors) {

final String name = origDescriptor.getName();

if ("class".equals(name)) {

continue; // No point in trying to set an object's class

}

if (getPropertyUtils().isReadable(orig, name) &&

getPropertyUtils().isWriteable(dest, name)) {

try {

final Object value =

getPropertyUtils().getSimpleProperty(orig, name);

copyProperty(dest, name, value);

} catch (final NoSuchMethodException e) {

// Should not happen

}

}

}

// org.apache.commons.beanutils.BeanUtilsBean#copyProperty

getPropertyUtils().setSimpleProperty(target, propName, value);

// org.apache.commons.beanutils.PropertyUtilsBean#setSimpleProperty

invokeMethod(writeMethod, bean, values);

1、 获取的是源对象的所有的属性

final PropertyDescriptor[] origDescriptors =  getPropertyDescriptors(orig);

2、如果属性是class,不复制

if ("class".equals_(name)) {    continue; // No point in trying to set an object's class}_

3、循环源对象的属性,做一些检验

copyProperty(dest, name, value);

1、会检验目标对象是否有源对象的属性,没有跳过

2、获取属性的名称类型

4、然后给目标对象设置,最终还是使用反射

method.invoke_(bean, values)_;

apache.commons#PropertyUtils

org.apache.commons.beanutils.PropertyUtilsBean#copyProperties

简单截取核心代码:

// org.apache.commons.beanutils.PropertyUtilsBean#copyProperties

final PropertyDescriptor[] origDescriptors =

getPropertyDescriptors(orig);

for (PropertyDescriptor origDescriptor : origDescriptors) {

final String name = origDescriptor.getName();

if (isReadable(orig, name) && isWriteable(dest, name)) {

try {

final Object value = getSimpleProperty(orig, name);

if (dest instanceof DynaBean) {

((DynaBean) dest).set(name, value);

} else {

setSimpleProperty(dest, name, value);

}

} catch (final NoSuchMethodException e) {

if (log.isDebugEnabled()) {

log.debug("Error writing to '" + name + "' on class '" + dest.getClass() + "'", e);

}

}

}

}

// org.apache.commons.beanutils.PropertyUtilsBean#invokeMethod

method.invoke(bean, values);

1、 获取的是源对象的所有的属性

final PropertyDescriptor[] origDescriptors =  getPropertyDescriptors(orig);

2、循环源对象的属性,然后给目标对象设置,最终还是使用反射

总结

结合使用说明以及相关的性能和原理分析,建议使用 org.springframework.beans.BeanUtils#copyPropertie

参考资料

Java编程技术乐园:分享干货技术,每天进步一点点,小的积累,带来大的改变!

扫描关注,后台回复99.9%的伙伴都很喜欢

java 文件拷贝保留原来的属性_Java常用属性拷贝工具类使用总结相关推荐

  1. java.util.concurrent(在并发编程中很常用的实用工具类)

    control意思即控制: current意思即同步(并发): 连起来就是控制同步(控制并发)concurrent.

  2. Java利用反射封装DBUtil,mysql万能增删改查工具类,附源码

    Java利用反射封装DBUtil,mysql万能增删改查工具类,附源码 等有时间再慢慢写代码注释吧,先把源码放出来.文章最后有整个项目的压缩包. ps:拓展 Java 原生MySQL JDBC 插入后 ...

  3. Java中Date类型如何向前向后滚动时间,( 附工具类)

    Java中的Date类型向前向后滚动时间(附工具类) 废话不多说,先看工具类: 1 import java.text.SimpleDateFormat; 2 import java.util.Cale ...

  4. java中常用的日期工具类

    java中常用的日期工具类 日期相关的类: package net.yto.ofclacct.core.util;import java.text.ParseException; import jav ...

  5. java实例属性_Java 静态属性与实例属性的初始化

    类的初始化包括静态属性的初始化和实例属性的初始化,在加载类过程中的准备阶段会给静态属性分配存储空间,并根据属性的类型设置初始值,例如 int 类型静态属性会设置初始值为 0,布尔类型静态属性会设置初始 ...

  6. java常用工具类_java(二):工作中常用到的工具类

    工作中大家要用到很多工具类,第三方的jar中有很多现成的工具类符合自己的项目需要,这个时候就不需要去重复造轮子了,从而节省了很多时间,大家可以利用这些时间去做其它重要的事情,如果没有符合自己的工具类, ...

  7. Java 中按文件名称分类,按文件大小分类,按照文件类型分类,按照最后修改时间分类的工具类

    在此博客中用到了文件操作的工具类,可以连接 Java中实现复制文件到文件,复制文件到文件夹,复制文件夹到文件,删除文件,删除文件夹,移动文件,移动文件夹的工具类 package cn.edu.hact ...

  8. java多态可以传匿名对象吗_Java复习笔记2--匿名类和多态

    匿名类 Anonymous classes enable you to make your code more concise. They enable you to declare and inst ...

  9. Java使用ftl模板文件生成Word,以及Word转换图片或Pdf工具类

    Java使用ftl模板文件生成Word 一.写在前面 最近在项目中使用打印功能,发现这个功能我已经写过多次了,下面这个文章的发步日期在2020年,不得不感慨时间之快啊. https://blog.cs ...

最新文章

  1. 【Qt】QCloseEvent的使用小结
  2. 老年机按键串号_2019年最适合买的老人机——AGM M5,4G全网通+支持微信
  3. java条码大小_java – 如何设置iText条码宽度?
  4. 协议层次及其服务模型
  5. Linux字符集安装文件,Linux下字符集的安装
  6. 语音处理入门——语音的声学处理
  7. web.py开发web 第一章 Hello World
  8. 839 - Not so Mobile
  9. 使用了未初始化的局部变量_Java 成员变量和局部变量
  10. SecureCRT自动化脚本编写
  11. wmic卸载程序命令_使用WMIC命令行卸载软件
  12. 深圳华睿彩印高温玻璃打印机介绍
  13. 国产BI报表工具中低调的优秀“模范生”——思迈特软件Smartbi
  14. 发现了一个好玩的SQL函数-soundex()
  15. 【18】CSS基础(3)——理解层叠式
  16. 数独解题思路——求解数独
  17. 吕思清老师口中的小艺是何许人也
  18. Springboot 启动命令中–spring.config.location不生效问题
  19. C语言实现RC4加密算法
  20. FISCO BCOS——SmartDev-Contract——Traceability商品溯源合约案例分析

热门文章

  1. OpenCV_Viz——OpenCV中Viz的模块编译的无法解析的外部符号BUG
  2. 绝对爆笑,虽然我知道可能和别的人雷同,但欢声笑语不雷同不是么?
  3. Boost.Geometry中的几何要素(Primitives)
  4. LINODE优惠码与服务器搭建
  5. springboot2.x 集成百度 ui-dgenerator生成分布式唯一id
  6. 创业者必知的股权分配
  7. 微分销有哪些正确的推广方式?
  8. 让你自己制作的木马和病毒用360安全卫士杀不出。加壳,免杀,加花,捆绑,压缩。
  9. python合并word表格_python合并word
  10. 计算机网络实训报告动态路由,实验报告OSPF动态路由的配置