Neal Gafter’s Super Type Tokens jdk 5 generics 추가 되면서 java.lang.Class를 제네릭 타입으로 바꿀수 있다 예를 들면 String.class를 지금은 Class으로 Joshua Bloch 말하는 THC, or Typesafe Heterogenous Container pattern이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package com.github.sejoung.codetest.generics.nealgafter;import java.util.HashMap;import java.util.Map;public class Favorites { private Map<Class<?>, Object> favorites = new HashMap <Class<?>, Object>(); public <T> void setFavorite (Class<T> klass, T thing) { favorites.put(klass, thing); } public <T> T getFavorite (Class<T> klass) { return klass.cast(favorites.get(klass)); } public static void main (String[] args) { Favorites f = new Favorites (); f.setFavorite(String.class, "Java" ); f.setFavorite(Integer.class, 0xcafebabe ); String s = f.getFavorite(String.class); int i = f.getFavorite(Integer.class); System.out.println(s); System.out.println(i); } }
위와 같은 코드를 타입 안전하고 컴파일시에 문제에 대해 판단할수 있다. 하지만 위에 코드는 제약이 있음니다.
아래의 코드를 추가하면 이레이져에 의해 문제가 됩니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package com.github.sejoung.codetest.generics.nealgafter;import java.util.Collections;import java.util.HashMap;import java.util.List;import java.util.Map;public class Favorites { private Map<Class<?>, Object> favorites = new HashMap <Class<?>, Object>(); public <T> void setFavorite (Class<T> klass, T thing) { favorites.put(klass, thing); } public <T> T getFavorite (Class<T> klass) { return klass.cast(favorites.get(klass)); } public static void main (String[] args) { Favorites f = new Favorites (); f.setFavorite(String.class, "Java" ); f.setFavorite(Integer.class, 0xcafebabe ); f.setFavorite (List<String>.class, Collections.emptyList ()); String s = f.getFavorite(String.class); int i = f.getFavorite(Integer.class); System.out.println(s); System.out.println(i); } }
컴파일 메시지
1 2 3 4 5 6 7 Error:(23, 37) java: <identifier> expected Error:(23, 42) java: <identifier> expected Error:(28, 27) java: <identifier> expected Error:(28, 29) java: <identifier> expected Error:(29, 27) java: <identifier> expected Error:(29, 29) java: <identifier> expected Error:(31, 2) java: reached end of file while parsing
위에 문제를 해결하기 위해 아래와 같은 방법을 사용하였다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 package com.github.sejoung.codetest.generics.nealgafter;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.ParameterizedType;import java.lang.reflect.Type;import java.util.ArrayList;import java.util.List;public abstract class TypeReference <T> { private final Type type; private volatile Constructor<?> constructor; protected TypeReference () { Type superclass = getClass().getGenericSuperclass(); if (superclass instanceof Class) { throw new RuntimeException ("Missing type parameter." ); } this .type = ((ParameterizedType) superclass).getActualTypeArguments()[0 ]; } @SuppressWarnings("unchecked") public T newInstance () throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { if (constructor == null ) { Class<?> rawType = type instanceof Class<?> ? (Class<?>) type : (Class<?>) ((ParameterizedType) type).getRawType(); constructor = rawType.getConstructor(); } return (T) constructor.newInstance(); } public Type getType () { return this .type; } public static void main (String[] args) throws Exception { List<String> l1 = new TypeReference <ArrayList<String>>(){}.newInstance(); List l2 = new TypeReference <ArrayList>() {}.newInstance(); } }
참조