【Java 代码实例 14】BeanUtils用法详解,附源码分析

【Java 代码实例 14】BeanUtils用法详解,附源码分析目录一、org.apache.commons.beanutils.BeanUtils简介二、使用的前置条件三、添加pom四、代码实例1、为属性赋值2、拷贝对象,为对象赋值3、map转bean4、bean转map五、Apache的BeanUtils与Spring的BeanUtils一、org.apache.commons.beanutils.BeanUtils简介BeanUtils是ApacheCommons组件的成员之一,主要用于简化JavaBean封装数据的操作。​简化反射封装参数的步骤,给对象封

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

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

在这里插入图片描述

一、org.apache.commons.beanutils.BeanUtils简介

BeanUtilsApache Commons组件的成员之一,主要用于简化JavaBean封装数据的操作。​
简化反射封装参数的步骤,给对象封装参数,好处是BeanUtils给对象封装参数的时候会进行类型自动转换。

二、使用的前置条件

  1. 类//必须使用public修饰
  2. 提供无参数的构造器
  3. 提供gettersetter方法访问属性

三、添加pom

<dependency>
     <groupId>commons-beanutils</groupId>
     <artifactId>commons-beanutils</artifactId>
     <version>1.9.4</version>
</dependency>

四、org.apache.commons.beanutils.BeanUtils代码实例

在这里插入图片描述

1、为属性赋值

private static void setUserProperty() throws Exception { 
   
    Worker worker = new Worker();

    BeanUtils.setProperty(worker, "id", "1");

    BeanUtils.setProperty(worker, "name", "哪吒");

    BeanUtils.setProperty(worker, "age", "28");

    System.out.println("id:"+ BeanUtils.getProperty(worker, "id"));

    System.out.println(worker);
}

2、拷贝对象,为对象赋值

private static void cloneBean() throws Exception { 
   
    Worker worker1 = new Worker(3,"哪吒",18);
    // 拷贝对象
    Object object = BeanUtils.cloneBean(worker1);
    Worker worker2 = (Worker)object;
    System.out.println(worker2);//Worker{id=3, name='哪吒', age=18}
    System.out.println("worker1==worker2 : "+(worker1==worker2));//false

    // 拷贝对象属性
    Worker worker3 = new Worker();
    BeanUtils.copyProperties(worker3,worker1);
    System.out.println(worker3);//Worker{id=3, name='哪吒', age=18}
    System.out.println("worker1==worker3 : "+(worker1==worker3));//false

    // 为属性赋值
    Worker worker4 = new Worker();
    BeanUtils.copyProperty(worker4,"age",30);
    System.out.println(worker4);//Worker{id=0, name='null', age=30}
}

3、map转bean

private static void mapToBean() throws Exception { 
   
    Map<String, Object> map = new HashMap<String, Object>();
    map.put("id",2);
    map.put("name","哪吒");
    map.put("age",29);
    Worker user = new Worker();
    BeanUtils.populate(user,map);
    System.out.println(user);
}

4、bean转map

private static void beanToMap() throws Exception { 
   
    Worker worker = new Worker(4,"哪吒编程",18);
    Map<String, String> map = BeanUtils.describe(worker);
    System.out.println(map);//{name=哪吒, id=4, age=18}

    // 为什么返回值是一个数组呢?
    String[] names = BeanUtils.getArrayProperty(worker, "name");
    System.out.println(names[0]);
}

五、Apache的BeanUtils与Spring的BeanUtils

在这里插入图片描述
默认情况下,使用org.apache.commons.beanutils.BeanUtils对复杂对象是进行的浅拷贝,但是由于Apache下的BeanUtils对象拷贝性能太差,不建议使用,这在阿里巴巴Java开发规约插件上也明确指出:

Ali-Check | 避免用Apache Beanutils进行属性的copy。

到这里你可能会疑惑,为什么会出现拷贝性能差的情况呢?

因为在对对象进行拷贝的时候添加很多的校验,比如像类型转换,甚至还校验了对象所属类的访问权限,可以说校验是相当的复杂,这也就是造成性能差的根本原因,我们看下它的具体代码实现:

public void copyProperties(final Object dest, final Object orig)
        throws IllegalAccessException, InvocationTargetException { 
   

        // Validate existence of the specified beans
        if (dest == null) { 
   
            throw new IllegalArgumentException
                    ("No destination bean specified");
        }
        if (orig == null) { 
   
            throw new IllegalArgumentException("No origin bean specified");
        }
        if (log.isDebugEnabled()) { 
   
            log.debug("BeanUtils.copyProperties(" + dest + ", " +
                      orig + ")");
        }

        // Copy the properties, converting as necessary
        if (orig instanceof DynaBean) { 
   
            final DynaProperty[] origDescriptors =
                ((DynaBean) orig).getDynaClass().getDynaProperties();
            for (DynaProperty origDescriptor : origDescriptors) { 
   
                final String name = origDescriptor.getName();
                // Need to check isReadable() for WrapDynaBean
                // (see Jira issue# BEANUTILS-61)
                if (getPropertyUtils().isReadable(orig, name) &&
                    getPropertyUtils().isWriteable(dest, name)) { 
   
                    final Object value = ((DynaBean) orig).get(name);
                    copyProperty(dest, name, value);
                }
            }
        } else if (orig instanceof Map) { 
   
            @SuppressWarnings("unchecked")
            final
            // Map properties are always of type <String, Object>
            Map<String, Object> propMap = (Map<String, Object>) orig;
            for (final Map.Entry<String, Object> entry : propMap.entrySet()) { 
   
                final String name = entry.getKey();
                if (getPropertyUtils().isWriteable(dest, name)) { 
   
                    copyProperty(dest, name, entry.getValue());
                }
            }
        } else /* if (orig is a standard JavaBean) */ { 
   
            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.springframework.beans.BeanUtils是使用 copyProperties方法进行拷贝,不过实现的方式相对于前者要来得简单得多了,可以说是非常的简单,就是根据两个对象属性的名字进行匹配,做简单的 get/set,仅检查属性的可访问性。具体实现如下:

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<String> 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);
						}
					}
				}
			}
		}
	}

从上面的实现源码可以看到:成员变量赋值是基于目标对象的成员列表,并且会跳过ignore以及在源对象中不存在的属性,所以这个方法是安全的,不会因为两个对象之间的结构差异导致错误,但是必须保证同名的两个成员变量类型相同。
以上简要的分析两种BeanUtils的具体实现以及性能相关的分析,得出结论:Apache下的BeanUtils由于各种繁琐的校验以及可访问性的校验等等,导致性能较差,故实际开发中不建议使用,可以使用 Spring的BeanUtils

六、org.springframework.beans.BeanUtils代码实例

1、实例化

package com.guor.beanutil.spring;

import com.guor.beanutil.Worker;
import org.junit.Test;
import org.springframework.beans.BeanUtils;

public class SpringBeanUtilsTest { 
   
    @Test
    public void testInstantiate() throws Exception{ 
   
        //通过无参数构造函数实例化
        Object obj = BeanUtils.instantiateClass(Worker.class);
        if(obj instanceof Worker) { 
   
            System.out.println(((Worker) obj).getNezha());//哪吒
        }

        //通过有参数构造函数实例化
        Object obj2 = BeanUtils.instantiateClass(Worker.class.getDeclaredConstructor(String.class), "哪吒编程");
        if(obj2 instanceof Worker) { 
   
            System.out.println(((Worker) obj2).getNezha());//哪吒编程
        }
    }
}

在这里插入图片描述

2、查找方法

(1)无参调用

@Test
public void testFindDeclaredMethod() throws Exception { 
   
    Worker worker = new Worker();
    worker.setId(8);
    worker.setName("哪吒");

    Method method = BeanUtils.findDeclaredMethod(Worker.class, "getName");
    Object name = method.invoke(worker);
    System.out.println(name);//哪吒
}

(2)有参调用

@Test
public void testPropertyDescriptor2() throws Exception { 
   
    Worker worker = new Worker();
    worker.setId(10);
    worker.setName("哪吒");

    Method method = BeanUtils.findMethod(Worker.class, "sayMsg",String.class,String.class);
    method.invoke(worker,"哪吒","我很帅");//哪吒 say :我很帅
}

(3)如果找不到方法
在这里插入图片描述

3、查找属性

@Test
public void testPropertyDescriptor() throws Exception { 
   
    Worker worker = new Worker();
    worker.setId(10);
    worker.setName("哪吒");

    //获取属性
    PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(Worker.class, "name");

    //获取属性的get方法
    Method getMethod = pd.getReadMethod();
    Object name = getMethod.invoke(worker);
    System.out.println(name);//哪吒

    //获取属性的get方法
    Method setMethod = pd.getWriteMethod();
    setMethod.invoke(worker, "哪吒编程");
    System.out.println(worker.getName());//哪吒编程
}

七、更多的Java代码实例

【Java 代码实例 4】javacompiler编译多java文件
【Java 代码实例 6】FileUtils、StringUtil、CollectionUtils、ArrayUtils(附代码示例)
【Java 代码实例 7】jsoup解析html
【Java 代码实例 8】qrcode生成二维码
【Java 代码实例 9】Java通过Process执行C# exe程序
【Java 代码实例 13】Java操作pdf的工具类itext

如果您有什么Java方面的需求,可以写在评论区,哪吒会一一进行回复,力争做到《你想知道的Java知识,哪吒都有》,加油!

在这里插入图片描述

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

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

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


相关推荐

  • 动态规划——背包问题(详解)

    动态规划——背包问题(详解)动态规划是我最早接触的算法,一开始非常简单,固定模板题,后来愈发愈发难起来了,条件,状态压缩等等,难点主要是,状态怎么表示,状态转移方程怎么写,这篇文章将会从背包五大问题详解,希望能帮助到大家去类比,思考其他动态规划题目。首先先来看看动态规划的定义:动态规划算法是通过拆分问题,定义问题状态和状态之间的关系,使得问题能够以递推(或者说分治)的方式去解决。动态规划算法的基本思想与分治法类似,也是将待求解的问题分解为若干个子问题(阶段),按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了有用的信息。

    2022年7月26日
    21
  • 中国成功发射第二颗北斗导航卫星,有感

    中国成功发射第二颗北斗导航卫星,有感首先,听到这个是心情很激动,觉得祖国离强国的距离又近一步。但又在想何时我想的卫星定位可以象GPS那样广范应用。我以前也做过几个相关项目,如果可以用自己国家的我一定会放弃GPS,为我国的3S发展出自己的一份力。 第一次自己写,写的很少。只是一点感想。

    2022年7月27日
    5
  • crontab的用法_crontab怎么读

    crontab的用法_crontab怎么读crontab命令参数-uuser:用来设定某个用户的crontab服务,例如,“-uixdba”表示设定ixdba用户的crontab服务,此参数一般有root用户来运行。file:file是命令文件的名字,表示将file做为crontab的任务列表文件并载入crontab。如果在命令行中没有指定这个文件,crontab命令将接受标准输入(键盘)上键入的命令,并将它们载入cronta…

    2022年8月24日
    4
  • applicationContext.xml配置简介「建议收藏」

    applicationContext.xml配置简介「建议收藏」spring的配置文件applicationContext.xml中的一些配置的作用。1.配置组件扫描器,使用注解方式开发<context:component-scanbase-package=”com.item.ikell”/>表示启动spring的组件扫描功能(从spring2.5版本开始)。即Spring容器初始化时,扫描base-package包或者子包下面的…

    2022年7月13日
    13
  • 右下角 弹出框 DIV 广告

    右下角 弹出框 DIV 广告

    2021年8月15日
    43
  • UDP协议 sendto 和 recvfrom 浅析与示例

    UDP协议 sendto 和 recvfrom 浅析与示例UDP(userdatagramprotocol)用户数据报协议,属于传输层。UDP是面向非连接的协议,它不与对方建立连接,而是直接把数据报发给对方。UDP无需建立类如三次握手的连接,使得通信效

    2022年7月1日
    27

发表回复

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

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