反射獲取類或對象屬性和值

       最近在開發過程中,由於部分常量配置在接口而非枚舉中,當我們需要通過屬性名去獲取具體接口中常量對應的值時,或是要獲取該接口中所有常量名和對應值的鍵值對集合,顯得有些麻煩或是無從下手,故這裏封裝一個通用的工具類來滿足此類需求(擴展到類和對象中),做以下總結。

      大致思路:定義 ReflectObjectUtil 工具類,通過反射獲取類或對象信息,並將對應信息組裝,按照要求的格式返回。

1. 測試實體

/** 測試實體Person
 *
 * @author [email protected]
 * @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 [email protected]
 * @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: 做map轉換記得寫鍵值衝突策略,養成好習慣,這裏採用後者覆蓋,(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 = ReflectObjectUtil.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 = ReflectObjectUtil.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 = ReflectObjectUtil.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 = ReflectObjectUtil.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 = ReflectObjectUtil.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 = ReflectObjectUtil.getFinalValues(Constant.class);

測試結果:

 

9. 測試用例彙總:

/**
 * ReflectObjectUtil工具類測試(測試全部通過)
 *
 * @author [email protected]
 * @version 1.0.0
 * @date 2019-05-08 14:26
 */
public class Test1 {

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章