Open leeyuunsung opened 1 year ago
public class GenericTypeInfer {
static class Super<T> {
T value;
}
public static void main(String[] args) throws NoSuchFieldException {
Super<String> stringSuper = new Super<>();
System.out.println(stringSuper.getClass().getDeclaredField("value").getType());
Type type = (new Super<String>(){}).getClass().getGenericSuperclass();
ParameterizedType pType = (ParameterizedType) type;
Type actualTypeArgument = pType.getActualTypeArguments()[0];
System.out.println(actualTypeArgument);
}
}
public abstract class TypeRef<T> {
private final Type type;
protected TypeRef() {
ParameterizedType superclass = (ParameterizedType) getClass().getGenericSuperclass();
type = superclass.getActualTypeArguments()[0];
}
@Override
public boolean equals(Object o) {
return o instanceof TypeRef && ((TypeRef)o).type.equals(type);
}
@Override
public int hashCode() {
return type.hashCode();
}
public Type getType() {
return type;
}
}
public class Favorites2 {
private final Map<TypeRef<?>, Object> favorites = new HashMap<>();
public <T> void put(TypeRef<T> typeRef, T thing) {
favorites.put(typeRef, thing);
}
@SuppressWarnings("unchecked")
public <T> T get(TypeRef<T> typeRref) {
return (T)(favorites.get(typeRref));
}
public static void main(String[] args) {
Favorites2 f = new Favorites2();
TypeRef<List<String>> stringTypeRef = new TypeRef<>() {};
System.out.println(stringTypeRef.getType());
TypeRef<List<Integer>> integerTypeRef = new TypeRef<>() {};
System.out.println(integerTypeRef.getType());
f.put(stringTypeRef, List.of("a", "b", "c"));
f.put(integerTypeRef, List.of(1, 2, 3));
f.get(stringTypeRef).forEach(System.out::println);
f.get(integerTypeRef).forEach(System.out::println);
}
}
단, TypeRef
도 아래와 같은 상황처럼 우회해서 사용하게 될 경우 type cast exception 이 발생한다
class Oops {
static Favorites2 f = new Favorites2();
static <T> List<T> favoriteList() {
TypeRef<List<T>> ref = new TypeRef<>() {};
System.out.println(ref.getType());
List<T> result = f.get(ref);
if (result == null) {
result = new ArrayList<T>();
f.put(ref, result);
}
return result;
}
public static void main(String[] args) {
List<String> ls = favoriteList();
List<Integer> li = favoriteList();
li.add(1);
for (String s : ls) System.out.println(s);
}
}
AnnotatedElement.<T extends Annotation> T getAnnotation(Class<T> annotationClass);
.asSubclass(Annotation.class)
// 코드 33-5 asSubclass를 사용해 한정적 타입 토큰을 안전하게 형변환한다. (204쪽)
public class PrintAnnotation {
static Annotation getAnnotation(AnnotatedElement element, String annotationTypeName) {
Class<?> annotationType = null; // 비한정적 타입 토큰
try {
annotationType = Class.forName(annotationTypeName);
} catch (Exception ex) {
throw new IllegalArgumentException(ex);
}
return element.getAnnotation(annotationType.asSubclass(Annotation.class));
}
// 명시한 클래스의 명시한 애너테이션을 출력하는 테스트 프로그램
public static void main(String[] args) throws Exception {
System.out.println(getAnnotation(MyService.class, FindMe.class.getName()));
}
}
아이템 33. 타입 안전 이종 컨테이너를 고려하라.
핵심 정리: 타입 토큰을 사용한 타입 안전 이종 컨테이너
Map
,Set
,Optional
, ...