1 概述
- 開發過程中如果需要編寫比較通用的代碼時,經常需要使用到泛型;
- 但有時候會被無法獲取到泛型類型而困擾,所以寫下此篇作為筆記;
2 常用獲取泛型類型方法
public class GenericTest {
public static void main(String[] args) {
// 1 false trag為E 錯誤獲取方式。
List<String> list1 = new ArrayList<>();
list1.add("test1");
System.out.println(genericClassName(list1));
// 2 true trag為class java.lang.String 匿名內部類獲取方式。
List<String> list2 = new ArrayList<String>() {
};
list2.add("test2");
System.out.println(genericClassName(list2));
// 3 true trag為class java.lang.String 額外傳遞匿名內部類獲取方式,這種更為常見。
List<String> list3 = new ArrayList<>();
list3.add("test3");
System.out.println(genericClassName(list3, new TypeReference<String>() {
}));
}
/**
* 獲取泛型類型
*
* @param list
* @param <T>
*/
private static <T> boolean genericClassName(List<T> list) {
Type type = list.getClass().getGenericSuperclass();
Type trag = ((ParameterizedType) type).getActualTypeArguments()[0];
T t = list.get(0);
return t.getClass().equals(trag);
}
/**
* 獲取泛型類型(更為常見,如:RestTemplate、FastJson、Jackson、Gson都是采用這種方式)
* 額外入參變量來存儲泛型類型來傳遞
*
* @param list
* @param <T>
*/
private static <T> boolean genericClassName(List<T> list, TypeReference<T> typeReference) {
Type type = typeReference.getClass().getGenericSuperclass();
Type trag = ((ParameterizedType) type).getActualTypeArguments()[0];
T t = list.get(0);
return t.getClass().equals(trag);
}
/**
* 自定義類型引用類
*/
static class TypeReference<T> {
}
}
3 源碼:RestTemplate為例
public static void main(String[] args) {
RestTemplate restTemplate = new RestTemplate();
String url = "http://test.test.com";
HttpMethod method = HttpMethod.GET;
HttpEntity httpEntity = null;
ParameterizedTypeReference<Map<String, Object>> typeReference = new ParameterizedTypeReference<Map<String, Object>>(){};
Map<String, ?> uriVariables = null;
// public <T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity,ParameterizedTypeReference<T> responseType, Map<String, ?> uriVariables)
ResponseEntity<Map<String, Object>> responseEntity = restTemplate.exchange(url, method, httpEntity, typeReference, uriVariables);
Map<String, Object> body = responseEntity.getBody();
}
- ParameterizedTypeReference類
public abstract class ParameterizedTypeReference<T> {
private final Type type;
protected ParameterizedTypeReference() {
// 與第2章節實現是類似,但對邊界條件的檢查更為全面,健壯性更好些
Class<?> parameterizedTypeReferenceSubclass = findParameterizedTypeReferenceSubclass(this.getClass());
Type type = parameterizedTypeReferenceSubclass.getGenericSuperclass();
ParameterizedType parameterizedType = (ParameterizedType)type;
this.type = parameterizedType.getActualTypeArguments()[0];
}
public Type getType() {
return this.type;
}
private static Class<?> findParameterizedTypeReferenceSubclass(Class<?> child) {
Class<?> parent = child.getSuperclass();
if (Object.class == parent) {
throw new IllegalStateException("Expected ParameterizedTypeReference superclass");
} else {
return ParameterizedTypeReference.class == parent ? child : findParameterizedTypeReferenceSubclass(parent);
}
}
}