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