大多数人不知道的Java知识 - Java内省机制

package com.nobody;

import java.beans.*;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

import java.util.UUID;

/**

  • @Description

  • @Author Mr.nobody

  • @Date 2021/3/23

  • @Version 1.0.0

*/

public class Demo {

public static void main(String[] args)

throws IntrospectionException, InvocationTargetException, IllegalAccessException {

// 不内省父类的信息,第二个参数stopClass代表从stopClass开始往上的父类不再内省

BeanInfo beanInfo = Introspector.getBeanInfo(Person.class, Object.class);

Person person = new Person(UUID.randomUUID().toString(), “Mr_nobody”, 18);

PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {

Class<?> propertyType = propertyDescriptor.getPropertyType();

String propertyName = propertyDescriptor.getName();

Method readMethod = propertyDescriptor.getReadMethod();

Method writeMethod = propertyDescriptor.getWriteMethod();

System.out.println(“属性名:” + propertyName);

System.out.println(“属性类型:” + propertyType);

System.out.println(“写方法名:” + writeMethod.getName());

System.out.println(“读方法名:” + readMethod.getName());

if (“age”.equals(propertyName)) {

writeMethod.invoke(person, 20);

}

System.out.println(“属性值:” + readMethod.invoke(person));

System.out.println(“------------------------------------------”);

}

}

}

输出结果:

属性名:age

属性类型:int

写方法名:setAge

读方法名:getAge

属性值:20


属性名:id

属性类型:class java.lang.String

写方法名:setId

读方法名:getId

属性值:a6ccda55-c895-438e-893f-7fa448aba35a


属性名:name

属性类型:class java.lang.String

写方法名:setName

读方法名:getName

属性值:Mr_nobody


当然,除了从BeanInfo对象获取PropertyDescriptor对象,也可以直接new的方式获取。

PropertyDescriptor namePropertyDescriptor = new PropertyDescriptor(“name”, Person.class);

MethodDescriptor

===========================================================================

java.beans.MethodDescriptor,即方法描述器,通过它可以获取到类相关的方法,如下所示:

package com.nobody;

import java.beans.*;

import java.lang.reflect.Method;

import java.lang.reflect.Type;

/**

  • @Description

  • @Author Mr.nobody

  • @Date 2021/3/23

  • @Version 1.0.0

*/

public class Demo {

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

// 不内省父类的信息,第二个参数stopClass代表从stopClass开始往上的父类不再内省

BeanInfo beanInfo = Introspector.getBeanInfo(Person.class, Object.class);

MethodDescriptor[] methodDescriptors = beanInfo.getMethodDescriptors();

for (MethodDescriptor methodDescriptor : methodDescriptors) {

Method method = methodDescriptor.getMethod();

System.out.println(method);

System.out.println(“方法名:” + method.getName());

Type[] genericParameterTypes = method.getGenericParameterTypes();

if (genericParameterTypes != null) {

for (Type genericParameterType : genericParameterTypes) {

System.out.println(“方法参数类型:” + genericParameterType.getTypeName());

}

}

Class<?> returnType = method.getReturnType();

System.out.println(“方法返回类型:” + returnType.getTypeName());

System.out.println(“---------------------------”);

}

}

}

输出结果如下:

public java.lang.String com.nobody.Person.getName()

方法名:getName

方法返回类型:java.lang.String


public void com.nobody.Person.setId(java.lang.String)

方法名:setId

方法参数类型:java.lang.String

方法返回类型:void


public void com.nobody.Person.setAge(int)

方法名:setAge

方法参数类型:int

方法返回类型:void


public void com.nobody.Person.setName(java.lang.String)

方法名:setName

方法参数类型:java.lang.String

方法返回类型:void


public int com.nobody.Person.getAge()

方法名:getAge

方法返回类型:int


public java.lang.String com.nobody.Person.getId()

方法名:getId

方法返回类型:java.lang.String


public java.lang.String com.nobody.Person.toString()

方法名:toString

方法返回类型:java.lang.String


内省应用

===============================================================

在项目实战中,我们一般使用最多的是 IntrospectorBeanInfoPropertyDescriptor,这三者结合起来使用。

比如,我们通过内省可以实现,JavaBean和Map互转,不同JavaBean对象属性拷贝等功能。

package com.nobody.util;

import java.beans.BeanInfo;

import java.beans.IntrospectionException;

import java.beans.Introspector;

import java.beans.PropertyDescriptor;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

import java.util.*;

/**

  • @Description Bean工具类

  • @Author Mr.nobody

  • @Date 2021/3/23

  • @Version 1.0.0

*/

public class BeanUtils {

public static Map<String, Object> beanToMap(T bean, boolean putIfNull)

throws IntrospectionException, InvocationTargetException, IllegalAccessException {

if (bean == null) {

return new HashMap<>();

}

Map<String, Object> returnMap = new HashMap<>();

// 获取bean的BeanInfo对象

BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass(), Object.class);

// 获取属性描述器

PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {

// 属性名

String propertyName = propertyDescriptor.getName();

// 获取该属性的值

Method readMethod = propertyDescriptor.getReadMethod();

// 属性的值

Object value = readMethod.invoke(bean);

if (value == null && !putIfNull) {

continue;

}

returnMap.put(propertyName, value);

}

return returnMap;

}

public static List<Map<String, Object>> beansToMaps(List beans, boolean putIfNull)

throws IllegalAccessException, IntrospectionException, InvocationTargetException {

if (null == beans || beans.size() == 0) {

return new ArrayList<>();

}

List<Map<String, Object>> result = new ArrayList<>(beans.size() + 1);

// 转换每一个bean

for (Object bean : beans) {

result.add(beanToMap(bean, putIfNull));

}

return result;

}

public static T mapToBean(Map<String, Object> map, Class clz)

throws IllegalAccessException, InstantiationException, IntrospectionException,

InvocationTargetException {

// 生成bean实例

T bean = clz.newInstance();

if (null == map) {

return bean;

}

BeanInfo beanInfo = Introspector.getBeanInfo(clz, Object.class);

PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {

// 属性名

String propertyName = propertyDescriptor.getName();

// 获取属性值

Object value = map.get(propertyName);

// 写入属性值

Method writeMethod = propertyDescriptor.getWriteMethod();

writeMethod.invoke(bean, value);

}

return bean;

}

public static List mapsToBeans(List<Map<String, Object>> maps, Class clz)

throws InvocationTargetException, IntrospectionException, InstantiationException,

IllegalAccessException {

if (null == maps || maps.size() == 0) {

return new ArrayList<>();

}

List result = new ArrayList<>();

for (Map<String, Object> map : maps) {

result.add(mapToBean(map, clz));

}

return result;

}

public static <T1, T2> void copyProperties(T1 origin, T2 dest, boolean setNull,

String[] excludeFieldNames)

throws IntrospectionException, InvocationTargetException, IllegalAccessException {

// 获取源类的BeanInfo对象

BeanInfo originBeanInfo = Introspector.getBeanInfo(origin.getClass(), Object.class);

// 获取源类的属性描述器

PropertyDescriptor[] originPropertyDescriptors = originBeanInfo.getPropertyDescriptors();

// 获取目标类的BeanInfo对象

BeanInfo destBeanInfo = Introspector.getBeanInfo(dest.getClass(), Object.class);

// 获取目标类的属性描述器

PropertyDescriptor[] destPropertyDescriptors = destBeanInfo.getPropertyDescriptors();

for (PropertyDescriptor propertyDescriptor : destPropertyDescriptors) {

String propertyName = propertyDescriptor.getName();

// 是否需要排除的属性

boolean excludeField = false;

if (excludeFieldNames != null) {

for (String excludeFieldName : excludeFieldNames) {

if (Objects.equals(excludeFieldName, propertyName)) {

excludeField = true;

break;

}

}

}

if (excludeField) {

continue;

}

// 遍历源类的所有属性,如果存在此属性则进行拷贝

for (PropertyDescriptor originPropertyDescriptor : originPropertyDescriptors) {

String originPropertyName = originPropertyDescriptor.getName();

if (Objects.equals(propertyName, originPropertyName)) {

// 读取属性值

Method readMethod = originPropertyDescriptor.getReadMethod();

Object srcValue = readMethod.invoke(origin);

if (srcValue != null || setNull) {

// 设置属性值

Method writeMethod = propertyDescriptor.getWriteMethod();

writeMethod.invoke(dest, srcValue);

}

break;

}

}

}

}

public static <T1, T2> void copyProperties(T1 origin, T2 dest)

throws IllegalAccessException, IntrospectionException, InvocationTargetException {

copyProperties(origin, dest, false, null);

}

}

以上是我们手写的JavaBean相关的转换工具类,当然市场上已经有很多成熟的工具包了,例如Apache的commons-beanutils包,里面就提供了许多实际开发中的应用场景会用到的API,大家不妨可以试用看看。

注意事项

===============================================================
开头提到JavaBean的get/set方法名要遵循某种规则,即驼峰规则。如下,我们将某个属性的get方法换个名字,例如将id属性的get方法名改为getUid()。那么我们就获取不到属性id的读方法的,即取到的是null。因为在取得id这个属性的属性描述器时,我们获取到了属性名,但是因为get方法没有遵循规则,所以调用getReadMethod()获取不到方法,所以出现空指针。
在这里插入图片描述

最后

这份清华大牛整理的进大厂必备的redis视频、面试题和技术文档

祝大家早日进入大厂,拿到满意的薪资和职级~~~加油!!

感谢大家的支持!!

image.png

ils包,里面就提供了许多实际开发中的应用场景会用到的API,大家不妨可以试用看看。

注意事项

===============================================================
开头提到JavaBean的get/set方法名要遵循某种规则,即驼峰规则。如下,我们将某个属性的get方法换个名字,例如将id属性的get方法名改为getUid()。那么我们就获取不到属性id的读方法的,即取到的是null。因为在取得id这个属性的属性描述器时,我们获取到了属性名,但是因为get方法没有遵循规则,所以调用getReadMethod()获取不到方法,所以出现空指针。
在这里插入图片描述

最后

这份清华大牛整理的进大厂必备的redis视频、面试题和技术文档

祝大家早日进入大厂,拿到满意的薪资和职级~~~加油!!

感谢大家的支持!!

[外链图片转存中…(img-sMoYAYky-1720099621798)]

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值