İşte size dayalı gelişmiş bir çözüm ParameterizedType.getActualTypeArguments
@Noah, @Lars Bohl ve diğerleri tarafından daha önce bahsedilen .
Uygulamada ilk küçük gelişme. Fabrika örneği değil, bir tür döndürmelidir. Kullanarak örneği döndürdüğünüzde Class.newInstance()
kullanım kapsamını azaltırsınız. Çünkü sadece argüman olmayan yapıcılar bu şekilde çağrılabilir. Daha iyi bir yol, bir tür döndürmek ve istemcinin hangi kurucuyu çağırmak istediğini seçmesine izin vermektir:
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);
}
}
}
İşte bir kullanım örnekleri. @Lars Bohl, geneneric'i genişletme yoluyla elde etmenin sadece signe bir yolunu gösterdi. @noah yalnızca ile bir örnek oluşturarak {}
. İşte her iki durumu da gösteren testler:
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);
}
}
Not: Eğer müşterileri zorlayabilir TypeReference
hep kullanım {}
örneği bu sınıf soyut yaparak oluşturulduğunda: public abstract class TypeReference<T>
. Bunu yapmadım, sadece silinen test durumunu göstermek için.