यहाँ एक बेहतर समाधान है, पर आधारित है ParameterizedType.getActualTypeArguments
पहले से ही @ जनाब, @ लार्स बोहल और कुछ अन्य लोगों द्वारा उल्लिखित है।
कार्यान्वयन में पहला छोटा सुधार। फैक्ट्री को वापस नहीं आना चाहिए, लेकिन एक प्रकार। जैसे ही आप उदाहरण का उपयोग करके वापस आते हैं, 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);
}
}
}
यहाँ एक उपयोग उदाहरण है। @ लार्स बोहल ने विस्तार के माध्यम से पुन: जेनराइक प्राप्त करने का केवल एक संकेत तरीका दिखाया है। @ केवल के साथ एक उदाहरण बनाने के माध्यम से {}
। यहाँ दोनों मामलों को प्रदर्शित करने के लिए परीक्षण दिए गए हैं:
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);
}
}
ध्यान दें: आप इस वर्ग को अमूर्त बनाकर उदाहरण के रूप में TypeReference
उपयोग किए {}
जाने पर हमेशा ग्राहकों को मजबूर कर सकते हैं public abstract class TypeReference<T>
:। मैंने ऐसा नहीं किया है, केवल मिटाए गए मामले को दिखाने के लिए।