ParameterizedType.getActualTypeArguments
@noah, @Lars Bohl 및 다른 사람들이 이미 언급 한 개선 된 솔루션이 있습니다.
구현에서 첫 번째 작은 개선. 팩토리는 인스턴스가 아니라 유형을 반환해야합니다. 를 사용하여 인스턴스를 반환하자마자 사용 Class.newInstance()
범위가 줄어 듭니다. 인수가없는 생성자 만 이와 같이 호출 할 수 있기 때문입니다. 더 좋은 방법은 형식을 반환하고 클라이언트가 호출 할 생성자를 선택할 수 있도록하는 것입니다.
public class TypeReference<T> {
public Class<T> type(){
try {
ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
if (pt.getActualTypeArguments() == null || pt.getActualTypeArguments().length == 0){
throw new IllegalStateException("Could not define type");
}
if (pt.getActualTypeArguments().length != 1){
throw new IllegalStateException("More than one type has been found");
}
Type type = pt.getActualTypeArguments()[0];
String typeAsString = type.getTypeName();
return (Class<T>) Class.forName(typeAsString);
} catch (Exception e){
throw new IllegalStateException("Could not identify type", e);
}
}
}
사용 예는 다음과 같습니다. @Lars Bohl은 확장을 통해 통일 된 제네릭을 얻는 방법을 보여 주었다. @noah을 사용하여 인스턴스를 생성해야합니다 {}
. 다음은 두 경우를 모두 보여주는 테스트입니다.
import java.lang.reflect.Constructor;
public class TypeReferenceTest {
private static final String NAME = "Peter";
private static class Person{
final String name;
Person(String name) {
this.name = name;
}
}
@Test
public void erased() {
TypeReference<Person> p = new TypeReference<>();
Assert.assertNotNull(p);
try {
p.type();
Assert.fail();
} catch (Exception e){
Assert.assertEquals("Could not identify type", e.getMessage());
}
}
@Test
public void reified() throws Exception {
TypeReference<Person> p = new TypeReference<Person>(){};
Assert.assertNotNull(p);
Assert.assertEquals(Person.class.getName(), p.type().getName());
Constructor ctor = p.type().getDeclaredConstructor(NAME.getClass());
Assert.assertNotNull(ctor);
Person person = (Person) ctor.newInstance(NAME);
Assert.assertEquals(NAME, person.name);
}
static class TypeReferencePerson extends TypeReference<Person>{}
@Test
public void reifiedExtenension() throws Exception {
TypeReference<Person> p = new TypeReferencePerson();
Assert.assertNotNull(p);
Assert.assertEquals(Person.class.getName(), p.type().getName());
Constructor ctor = p.type().getDeclaredConstructor(NAME.getClass());
Assert.assertNotNull(ctor);
Person person = (Person) ctor.newInstance(NAME);
Assert.assertEquals(NAME, person.name);
}
}
참고 : 이 클래스를 abstract :로 만들어 인스턴스가 생성 될 때 클라이언트가 TypeReference
항상 사용 하도록 할 수 있습니다 . 삭제하지 않은 테스트 사례 만 표시하기 위해 수행하지 않았습니다.{}
public abstract class TypeReference<T>