[实践总结] Java 反射实践总结 读取属性值,给属性赋值,类转map

通过反射读取属性值

    /**
     * 通过反射机制获取给定对象指定属性字段的值。
     * 此方法接收一个泛型对象 {@code T} 和一个字符串类型的字段名称,
     * 并尝试在该对象的类中查找具有匹配名称的属性描述符。
     * 它随后调用该属性的读取方法(getter)来获取并返回该字段的当前值。
     *
     * @param <T>       需要读取其字段值的对象类型
     * @param t         对象实例,其属性值将被读取
     * @param fieldName 要读取的属性字段名称
     * @return 字段的值,可以是任意类型,与目标字段的实际类型一致
     * @throws RuntimeException 如果在访问或读取属性值过程中发生异常,例如非法访问权限、
     *                          方法不存在或者Introspection异常时抛出此异常
     */
    public static <T> Object getFieldValue(T t, String fieldName) {
        // 检查传入的对象和字段名称是否为空
        if (t == null || fieldName == null || fieldName.isEmpty()) {
            throw new IllegalArgumentException("对象或字段名称不能为空");
        }
        try {
            // 创建属性描述符,用于获取读取方法
            PropertyDescriptor propertyDescriptor = new PropertyDescriptor(fieldName, t.getClass());
            // 获取属性的读取方法
            Method readMethod = propertyDescriptor.getReadMethod();
            // 如果找到读取方法,则调用它来获取属性值
            if (readMethod != null) {
                return readMethod.invoke(t);
            } else {
                // 如果没有找到读取方法,则抛出异常
                throw new RuntimeException("属性 '" + fieldName + "' 无法读取");
            }
        } catch (IllegalAccessException | InvocationTargetException | IntrospectionException e) {
            // 对于反射操作出现的异常,封装为运行时异常并抛出
            throw new RuntimeException("访问属性 '" + fieldName + "' 时发生错误", e);
        }
    }

@Test
public void testGetFieldValue() {
    User user1 = new User();
    user1.setName("user1");
    user1.setAge("19");
    user1.setNum("123456");
    Assert.assertEquals("user1", ReflectUtils.getFieldValue(user1, "name"));
    Assert.assertEquals("19", ReflectUtils.getFieldValue(user1, "age"));
    Assert.assertEquals("123456", ReflectUtils.getFieldValue(user1, "num"));
}

实践场景:已知属性名获取属性值

User user1 = new User();
user1.setName("user1");
user1.setAge("19");
user1.setNum("123456");

List<String> strings = Arrays.asList("name", "age", "num");
List<Object> collect = strings.stream().map(a -> ReflectUtils.getFieldValue(user1, a)).toList();
System.out.println(collect);

结果:
[user1, 19, 123456]

通过反射给属性赋值

    /**
     * 通过反射机制动态地为给定对象的指定属性设置值。
     *
     * @param <T>       对象类型
     * @param object    需要修改属性的对象,不能为空
     * @param fieldName 需要设置的属性名称,不能为空且不能是空字符串
     * @param value     将要赋予属性的新值
     * @throws IllegalArgumentException 如果传入的对象或字段名为空,或者找不到与字段名对应的setter方法时抛出异常
     * @throws RuntimeException         在尝试通过反射设置属性值时发生任何反射相关的异常(如IllegalAccessException, InvocationTargetException, IntrospectionException)时,包装原始异常并抛出RuntimeException
     */
    public static <T> void setFieldValue(final T object, final String fieldName, final Object value) {
        if (object == null || fieldName == null || fieldName.isEmpty()) {
            throw new IllegalArgumentException("Object or fieldName cannot be null/empty");
        }

        try {
            PropertyDescriptor propertyDescriptor = new PropertyDescriptor(fieldName, object.getClass());
            Method writeMethod = propertyDescriptor.getWriteMethod();

            if (writeMethod != null) {
                writeMethod.invoke(object, value);
            } else {
                System.err.println("未找到设置方法: " + fieldName);
            }
        } catch (IllegalAccessException | InvocationTargetException | IntrospectionException e) {
            throw new RuntimeException("通过反射设置属性时发生异常: " + e.getMessage(), e);
        }
    }

@Test
public void testSetFieldValue() {
    User user = new User();
    ReflectUtils.setFieldValue(user, "name", "user1");
    ReflectUtils.setFieldValue(user, "age", "19");
    ReflectUtils.setFieldValue(user, "num", "123456");
    Assert.assertEquals("user1", user.getName());
    Assert.assertEquals("19", user.getAge());
    Assert.assertEquals("123456", user.getNum());
}

实践场景: Map<String, List<String>> 结构体 转换为 对象类型

Map<String, List<String>> map = new HashMap<>();
map.put("name", Arrays.asList("name1", "name2", "name3"));
map.put("age", Arrays.asList("11", "23", "23"));
map.put("num", Arrays.asList("123", "234", "345"));

List<User> users = new ArrayList<>();

List<String> fields = new ArrayList<>(map.keySet());
int size = map.get(fields.get(0)).size();
for (int i = 0; i < size; i++) {
    User user1 = new User();
    for (String field : fields) {
        String value = map.get(field).get(i);
        ReflectUtils.setFieldValue(user1, field, value);
    }
    users.add(user1);
}

System.out.println(users);


结果:
[ReflectUtilsTest.User(name=name1, age=11, num=123), 
ReflectUtilsTest.User(name=name2, age=23, num=234), 
ReflectUtilsTest.User(name=name3, age=23, num=345)]

类转map

    /**
     * 将给定的实体对象转换为Map,其中键是属性名,值是属性值。
     * <p>
     * 此方法通过Java反射机制({@link Introspector})获取类的所有属性描述符,
     * 并调用getter方法来读取属性值。注意,此方法会忽略名为"serialVersionUID"的属性。
     *
     * @param <T>    实体类的类型
     * @param entity 需要转换为Map的对象实例
     * @return 包含对象属性名与对应属性值的映射关系的Map
     * @throws RuntimeException 当出现IntrospectionException、InvocationTargetException或IllegalAccessException时抛出
     */
    public static <T> Map<String, Object> beanToMap(T entity) {
        try {
            PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(entity.getClass(), Object.class).getPropertyDescriptors();
            Map<String, Object> map = new HashMap<>(propertyDescriptors.length);
            for (PropertyDescriptor property : propertyDescriptors) {
                String propertyName = property.getName();
                if ("serialVersionUID".equals(propertyName)) {
                    continue;
                }
                Method readMethod = property.getReadMethod();
                map.put(propertyName, readMethod.invoke(entity));
            }
            return map;
        } catch (IntrospectionException | InvocationTargetException | IllegalAccessException e) {
            throw new RuntimeException("Error occurred while converting entity to map", e);
        }
    }
  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值