反射获取类或对象属性和值

       最近在开发过程中,由于部分常量配置在接口而非枚举中,当我们需要通过属性名去获取具体接口中常量对应的值时,或是要获取该接口中所有常量名和对应值的键值对集合,显得有些麻烦或是无从下手,故这里封装一个通用的工具类来满足此类需求(扩展到类和对象中)做以下总结。

      大致思路:定义 ReflexObjectUtil 工具类,通过反射获取类或对象信息,并将对应信息组装,按照要求的格式返回。

1. 测试实体

/** 测试实体Person
 *
 * @author jiayuan9608@163.com
 * @version 1.0.0
 * @date 2019-05-08 14:19
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Person {

    private String name = "zhangsan";

    private byte sex = 1;

    private int age = 18;

    private String introduce = "niuBility";
}

2. 接口常量

/**
 * 测试接口常量demo
 *
 * @author jiayuan9608@163.com
 * @version 1.0.0
 * @date 2019-05-08 14:23
 */
public interface Constant {

    int CONFIG_INT1 = 1;

    int CONFIG_INT2 = 2;

    int CONFIG_INT3 = 3;

    String CONFIG_STRING1 = "1";

    String CONFIG_STRING2 = "2";

    String CONFIG_STRING3 = "3";
}

3. 获取单个对象的所有键值对(变量名-变量值)

通过泛型参数限定传入一个对象,该方法传入一个对象,返回该对象所有的属性-值。

注意:这里Collectors.toMap(key,value)中的value值不能为空,若对象属性值存在为空的情况,则会抛出空指针异常,查看toMap()方法源码,发现在map集合进行merge合并时进行了非空判断操作,如下:

反射获取类或对象属性和值

故这里使用Optional进行空值的包装,在为空时用0代替(看具体业务场景)。ps: 记得写键值冲突策略,养成好习惯,这里采用后者覆盖,(k1, k2) -> k2。

/**
     * 获取单个对象的所有键值对
     *
     * @param t
     * @param <T>
     * @return
     */
    public static <T> Map<String, Object> getKeyAndValue(T t) {
        Map<String, Object> map = Maps.newHashMap();
        Class clazz = (Class) t.getClass();
        Field[] fields = clazz.getDeclaredFields();
        map = Arrays.stream(fields).collect(Collectors.toMap(Field::getName, field -> {
            Object resultObj = null;
            field.setAccessible(true);
            try {
                resultObj = field.get(t);
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            return Optional.ofNullable(resultObj).orElse(0);
        }, (k1, k2) -> k2));
        return map;
    }

测试用例:

Map<String, Object> result1 = ReflexObjectUtil.getKeyAndValue(new Person());

测试结果:

反射获取类或对象属性和值

4. 获取单个对象指定键的值

/**
     * 获取单个对象指定键的值
     *
     * @param t
     * @param key
     * @param <T>
     * @return
     */
    public static <T> Object getValueByKey(T t, String key) {
        Class clazz = t.getClass();
        Field[] fields = clazz.getDeclaredFields();
        Field resultField = Arrays.stream(fields)
                .filter(field -> field.getName().equals(key))
                .findFirst()
                .get();
        Object obj = null;
        resultField.setAccessible(true);
        try {
            obj = resultField.get(t);
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return obj;
    }

测试用例:

Object result2 = ReflexObjectUtil.getValueByKey(new Person(), "name");

测试结果:

反射获取类或对象属性和值

5. 获取多个对象的所有键值对

此类需求较少~

/**
     * 获取多个对象的所有键值对
     *
     * @param objects
     * @return
     */
    public static List<Map<String, Object>> getKeyAndValues(List<Object> objects) {
        return objects.stream().map(obj -> {
            Class clazz = obj.getClass();
            return Arrays.stream(clazz.getDeclaredFields()).collect(Collectors.toMap(Field::getName, field -> {
                Object resultObj = null;
                field.setAccessible(true);
                try {
                    resultObj = field.get(obj);
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                return Optional.ofNullable(resultObj).orElse(0);
            }, (k1, k2) -> k2));
        }).collect(Collectors.toList());
    }

测试用例:

List<Map<String, Object>> result3 = ReflexObjectUtil.getKeyAndValues(Arrays.asList(new Person(), new Person()));

测试结果:

反射获取类或对象属性和值

6. 获取多个对象指定键的所有值

/**
     * 获取多个对象指定键的所有值
     *
     * @param objects
     * @param key
     * @return
     */
    public static List<Object> getValuesByKey(List<Object> objects, String key) {
        return objects.stream().map(obj -> {
            Class clazz = obj.getClass();
            return Arrays.stream(clazz.getDeclaredFields())
                    .filter(field -> field.getName().equals(key))
                    .map(field -> {
                        Object resultObj = null;
                        field.setAccessible(true);
                        try {
                            resultObj = field.get(obj);
                        } catch (IllegalArgumentException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                        return resultObj;
                    }).collect(Collectors.toList());
        }).collect(Collectors.toList());
    }

测试用例:

List<Object> result4 = ReflexObjectUtil.getValuesByKey(Arrays.asList(new Person(), new Person()), "name");

测试结果:

反射获取类或对象属性和值

7. 获取静态变量

以下适用与类或接口参数

/**
     * 获取静态变量
     *
     * @param clazz
     * @param key
     * @return
     */
    public static Object getValueByKey(Class<?> clazz, String key) {
        Field[] fields = clazz.getDeclaredFields();
        Field result = Arrays.stream(fields)
                .filter(field -> key.equals(field.getName()))
                .findFirst()
                .get();
        Object obj = null;
        try {
            obj = clazz.getField(result.getName()).get(null);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        return obj;
    }

测试用例:

String result5 = ReflexObjectUtil.getValueByKey(Constant.class, "CONFIG_INT1").toString();

测试结果:

反射获取类或对象属性和值

8. 获取类或接口中所有的常量

 /**
     * 获取类或接口中所有的常量
     *
     * @param clazz
     * @return
     */
    public static Map<String, Object> getFinalValues(Class<?> clazz) {
        Field[] fields = clazz.getDeclaredFields();
        return Arrays.stream(fields)
                .filter(field -> Modifier.isFinal(field.getModifiers()))
                .collect(Collectors.toMap(Field::getName, field -> {
                    Object obj = null;
                    try {
                        obj = clazz.getField(field.getName()).get(null);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (NoSuchFieldException e) {
                        e.printStackTrace();
                    }
                    return obj;
                }));
    }

测试用例:

Map<String, Object> result6 = ReflexObjectUtil.getFinalValues(Constant.class);

测试结果:

反射获取类或对象属性和值

 

9. 测试用例汇总:

/**
 * ReflexObjectUtil工具类测试(测试全部通过)
 *
 * @author jiayuan9608@163.com
 * @version 1.0.0
 * @date 2019-05-08 14:26
 */
public class Test1 {

    public static void main(String[] args) {
        Map<String, Object> result1 = ReflexObjectUtil.getKeyAndValue(new Person());
        Object result2 = ReflexObjectUtil.getValueByKey(new Person(), "name");
        List<Map<String, Object>> result3 = ReflexObjectUtil.getKeyAndValues(Arrays.asList(new Person(), new Person()));
        List<Object> result4 = ReflexObjectUtil.getValuesByKey(Arrays.asList(new Person(), new Person()), "name");
        String result5 = ReflexObjectUtil.getValueByKey(Constant.class, "CONFIG_INT1").toString();
        Map<String, Object> result6 = ReflexObjectUtil.getFinalValues(Constant.class);
    }
}

 

上一篇:java 放射的用法


下一篇:面经手册 · 第13篇《除了JDK、CGLIB,还有3种类代理方式?面试又卡住!》