जावा में प्रतिबिंब के साथ एक सामान्य पैरामीटर का प्रकार प्राप्त करें


143

क्या सामान्य पैरामीटर के प्रकार को प्राप्त करना संभव है?

एक उदाहरण:

public final class Voodoo {
    public static void chill(List<?> aListWithTypeSpiderMan) {
        // Here I'd like to get the Class-Object 'SpiderMan'
        Class typeOfTheList = ???;
    }

    public static void main(String... args) {
        chill(new ArrayList<SpiderMan>());
    }
}

जवाबों:


156

एक निर्माण, मैं एक बार ठोकर की तरह लग रहा था

Class<T> persistentClass = (Class<T>)
   ((ParameterizedType)getClass().getGenericSuperclass())
      .getActualTypeArguments()[0];

तो वहाँ कुछ प्रतिबिंब-जादू के आसपास लगता है कि मैं दुर्भाग्य से पूरी तरह से समझ में नहीं आता ... क्षमा करें।


2
लेकिन इसे अमूर्त घोषित करें। जब आप इसका उपयोग करना चाहते हैं, तब इसे इनलाइन को सब्स्क्राइब करें।
स्निकॉल

42
हालांकि यह बहुत पुराना है और किसी कारण से स्वीकार कर लिया गया है , मैंने इसे अस्वीकार कर दिया है क्योंकि यह बस सवाल का जवाब नहीं देता है। यह प्रश्न में दिए गए उदाहरण में "स्पाइडरमैन" नहीं देगा। यह कुछ स्थितियों में निस्संदेह उपयोगी है, लेकिन यह उस प्रश्न के लिए काम नहीं करता है जो पूछा गया था।
जॉन स्कीट

15
कोई भी ऐसा नहीं है जो एक जवाब के लिए "यह नहीं किया जा सकता" स्वीकार करने के बारे में है। हम यहाँ हैं क्योंकि हम हताश हैं।
एडिसन

14
मुझे यह अपवाद मिलता है: Exception in thread "main" java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType यह निश्चित नहीं है कि बाधा क्या है।
डिश

4
जैसे @Dish मैं सिर्फ एकjava.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
केनी वायलैंड

133

मैं समझाने के लिए @DerMike से उत्तर को तोड़ने की कोशिश करना चाहता हूं:

सबसे पहले, प्रकार के क्षरण का मतलब यह नहीं है कि जेडीके समाप्त हो जाता है रनटाइम में टाइप जानकारी को है। यह संकलन-समय प्रकार की जाँच और एक ही भाषा में सह-अस्तित्व के लिए क्रम प्रकार संगतता की अनुमति देने के लिए एक विधि है। जैसा कि कोड के इस ब्लॉक का तात्पर्य है, जेडीके मिटाए गए प्रकार की जानकारी को बरकरार रखता है - यह सिर्फ चेक किए गए कास्ट और सामान से जुड़ा नहीं है।

दूसरा, यह सामान्य प्रकार के सामान्य वर्ग को सामान्य प्रकार की जानकारी प्रदान करता है, ठोस प्रकार से पदानुक्रम की जाँच की जा रही है - यानी जेनेरिक प्रकार के मापदंडों के साथ एक अमूर्त अभिभावक वर्ग स्वयं के ठोस कार्यान्वयन के लिए अपने प्रकार के मापदंडों के अनुरूप ठोस प्रकार पा सकता है। यह सीधे इसे से विरासत में मिला है। यदि यह वर्ग गैर-सार और तात्कालिक था, या ठोस कार्यान्वयन दो स्तरों से नीचे था, तो यह काम नहीं करेगा (हालांकि थोड़ा सा जिम्मीइंग इसे एक से परे स्तर के किसी भी पूर्वनिर्धारित संख्या पर लागू कर सकता है, या सबसे कम कक्षा तक। एक्स जेनेरिक प्रकार के मापदंडों के साथ, एट वगैरह)।

वैसे भी, स्पष्टीकरण पर। यहाँ कोड फिर से, संदर्भ की आसानी के लिए लाइनों में अलग किया गया है:

1 # कक्षा का जेनेरिकप्रेम 0 ओएफटी क्लिक्स = 
2 # (कक्षा)
3 # ((परिमितीकृत प्रकार)
4 # getClass ()
5 # .गैजेनिकसुपरक्लास ())
6 # .getActualTypeArguments () [0];

बता दें कि 'हम' जेनेरिक प्रकारों के साथ सार वर्ग है जिसमें यह कोड होता है। इसे मोटे तौर पर अंदर बाहर पढ़ना:

  • लाइन 4 को वर्तमान ठोस वर्ग 'श्रेणी का उदाहरण मिलता है। यह हमारे तात्कालिक वंशज के ठोस प्रकार की पहचान करता है।
  • लाइन 5 को एक प्रकार के रूप में उस वर्ग का सुपरपेप मिलता है; यह हमलोग हैं। चूंकि हम एक पैरामीट्रिक प्रकार हैं, इसलिए हम खुद को ParameterizedType (पंक्ति 3) में सुरक्षित रूप से डाल सकते हैं। कुंजी यह है कि जब जावा इस प्रकार की वस्तु को निर्धारित करता है, तो यह नए पैरामीटाइज़रटाइप उदाहरण में हमारे प्रकार के मापदंडों के साथ प्रकार की जानकारी को जोड़ने के लिए बच्चे में मौजूद प्रकार की जानकारी का उपयोग करता है। तो अब हम अपने जेनेरिक के लिए ठोस प्रकार तक पहुँच सकते हैं।
  • कक्षा 6 में हमारे कोड में टाइप किए गए प्रकारों की श्रेणी क्रमबद्ध है, जैसा कि कक्षा कोड में घोषित किया गया है। इस उदाहरण के लिए हम पहला पैरामीटर निकालते हैं। यह एक प्रकार के रूप में वापस आता है।
  • पंक्ति 2 अंतिम प्रकार को एक कक्षा में वापस लाती है। यह सुरक्षित है क्योंकि हम जानते हैं कि हमारे जेनेरिक प्रकार के पैरामीटर किस प्रकार के लिए सक्षम हैं और पुष्टि कर सकते हैं कि वे सभी कक्षाएँ होंगे (मुझे यकीन नहीं है कि जावा में कैसे एक सामान्य पैरामीटर प्राप्त करने के बारे में जाना जाएगा जिनके पास कक्षा उदाहरण नहीं है इसके साथ जुड़ा हुआ है, वास्तव में)।

...और बस यही सब है। इसलिए हम अपने स्वयं के ठोस कार्यान्वयन से प्रकार की जानकारी को अपने आप में वापस धकेलते हैं, और इसका उपयोग एक वर्ग के हैंडल तक पहुंचने के लिए करते हैं। हम getGenericSuperclass () को दो स्तर तक बढ़ा सकते हैं, या getGenericSuperclass () को समाप्त कर सकते हैं और अपने लिए एक ठोस प्रकार के रूप में मान प्राप्त कर सकते हैं (चेतावनी: मैंने इन परिदृश्यों का परीक्षण नहीं किया है, वे मेरे लिए अभी तक नहीं आए हैं)।

यह मुश्किल हो जाता है यदि आपके ठोस बच्चे मनमाने ढंग से संख्याओं से दूर हो जाते हैं, या यदि आप ठोस हैं और अंतिम नहीं हैं, और विशेष रूप से मुश्किल है यदि आप अपने किसी भी (वैरिएबल डीप) बच्चों से अपेक्षा करते हैं कि वे अपने स्वयं के जेनेरिक हों। लेकिन आप आमतौर पर उन विचारों के इर्द-गिर्द डिजाइन कर सकते हैं, इसलिए यह आपको सबसे ज्यादा पसंद आता है।

आशा है कि यह किसी की मदद की! मैं मानता हूं कि यह पद प्राचीन है। मैं शायद इस स्पष्टीकरण को स्निप करूंगा और इसे अन्य सवालों के लिए रखूंगा।


3
बस आपके जवाब देने में "मुझे यकीन नहीं है कि जावा में एक सामान्य पैरामीटर प्राप्त करने के बारे में कैसे होगा, जिसके पास क्लास उदाहरण नहीं है, वास्तव में)": "यह संभव है अगर सामान्य वर्ग का पैरामीटर या तो" वाइल्डकार्ड एक्सप्रेशन "(कहते हैं:; कुछ एक्सक्लेव्स को बढ़ाता है) या" टाइप वेरिएबल "(कहते हैं: <टी> जहां टी एक सामान्य उपवर्ग से आता है)। दोनों ही मामलों में "टाइप" किए गए इंस्टेंस को "क्लास" में नहीं डाला जा सकता है क्योंकि प्रत्येक वीएम में दोनों के लिए एक अलग कार्यान्वयन हो सकता है जो टाइप इंटरफ़ेस को लागू करता है लेकिन सीधे java.lang.Class से प्राप्त नहीं होता है।
रॉबर्टो एंड्रेड

19

वास्तव में मुझे यह काम करने के लिए मिला है। निम्नलिखित स्निपेट पर विचार करें:

Method m;
Type[] genericParameterTypes = m.getGenericParameterTypes();
for (int i = 0; i < genericParameterTypes.length; i++) {
     if( genericParameterTypes[i] instanceof ParameterizedType ) {
                Type[] parameters = ((ParameterizedType)genericParameterTypes[i]).getActualTypeArguments();
//parameters[0] contains java.lang.String for method like "method(List<String> value)"

     }
 }

मैं jdk 1.6 का उपयोग कर रहा हूं


12
-1: यह प्रश्न में समस्या को हल नहीं करता है; यह आपको केवल विधि हस्ताक्षर में घोषित प्रकार देता है, वास्तविक रनटाइम प्रकार नहीं।
माइकल बोर्गवर्ड

5
ओपी के सवाल का जवाब नहीं हो सकता है, लेकिन यह एक उपयोगी तकनीक है।
dnault

3
यह एक पूरी तरह से अलग सवाल का जवाब है।
दाऊद इब्न करीम

सभी वास्तविक प्रकार प्राप्त करने के लिए आप m.getParameterTypes () को कॉल कर सकते हैं। यह उदाहरण के लिए "सूची" लौटाएगा।
बजे ली मीडोर

यदि GenericParameterTypes [i] एक उदाहरण नहीं है ParameterizedType, तो यह एक वर्ग हो सकता है। इसका मतलब है कि विधि के लिए एक विशेष तर्क बिल्कुल भी मानकीकृत नहीं है।
बजे ली मीडोर

18

"अनाम वर्ग" ट्रिक और सुपर टाइप टोकन से विचारों को लागू करके वास्तव में एक समाधान है :

public final class Voodoo {
    public static void chill(final List<?> aListWithSomeType) {
        // Here I'd like to get the Class-Object 'SpiderMan'
        System.out.println(aListWithSomeType.getClass().getGenericSuperclass());
        System.out.println(((ParameterizedType) aListWithSomeType
            .getClass()
            .getGenericSuperclass()).getActualTypeArguments()[0]);
    }
    public static void main(String... args) {
        chill(new ArrayList<SpiderMan>() {});
    }
}
class SpiderMan {
}

एक के निर्माण में चाल झूठ गुमनाम वर्ग , new ArrayList<SpiderMan>() {}, मूल (सरल) के स्थान पर new ArrayList<SpiderMan>()। एनोयमस क्लास (यदि संभव हो) का उपयोग यह सुनिश्चित करता है कि कंपाइलर SpiderManटाइप पैरामीटर को दिए गए प्रकार के तर्क के बारे में जानकारी रखता है List<?>। Voilà!


यह अप्रत्यक्ष रूप से प्रश्न का उत्तर देता है: मूल समस्या का कोई हल नहीं है। अपने सामान्य मापदंडों को बनाए रखने के प्रकार के लिए, इसे एक अन्य प्रकार, जैसे कि उपवर्ग में एम्बेड करना होगा। यह उदाहरण दिखाता है कि आपको चिल () में सामान्य प्रकार के पैरामीटर को पुनर्प्राप्त करने के लिए कॉलिंग कोड को बदलने की आवश्यकता है।
फ्लोरियन एफ

FYI करें, पहला लिंक मृत है
अश्विन शर्मा

@AshvinSharma मेरा मानना ​​है कि यहाँ वही सामग्री उपलब्ध है: rgomes.info/use-typetokens-to-retrieve-generic-parameters
Yann-Gaël Guéhénev

7

टाइप एरेस्योर की वजह से सूची के प्रकार को जानने का एकमात्र तरीका है कि किस प्रकार से विधि को पैरामीटर के रूप में पास किया जाए:

public class Main {

    public static void main(String[] args) {
        doStuff(new LinkedList<String>(), String.class);

    }

    public static <E> void doStuff(List<E> list, Class<E> clazz) {

    }

}

7

परिमाणित इंटरफ़ेस के जेनेरिक पैरामीटर ( #getGenericInterfaces का उपयोग करके ) के लिए @ DerMike के उत्तर के लिए परिशिष्ट ( दोहराव से बचने के लिए जावा -8 डिफ़ॉल्ट विधि के अंदर विधि):

import java.lang.reflect.ParameterizedType; 

public class ParametrizedStuff {

@SuppressWarnings("unchecked")
interface Awesomable<T> {
    default Class<T> parameterizedType() {
        return (Class<T>) ((ParameterizedType)
        this.getClass().getGenericInterfaces()[0])
            .getActualTypeArguments()[0];
    }
}

static class Beer {};
static class EstrellaGalicia implements Awesomable<Beer> {};

public static void main(String[] args) {
    System.out.println("Type is: " + new EstrellaGalicia().parameterizedType());
    // --> Type is: ParameterizedStuff$Beer
}

यह वह नहीं है जो मूल पोस्ट के लिए पूछ रहा था। यहाँ, आपने एक उपवर्ग बनाया है Awesomeable<Beer>। उस स्थिति में प्रकार की जानकारी संरक्षित है। यदि आप new Awesomable<Beer> ()विधि के लिए पास wt काम नहीं करेगा।
फ्लोरियन एफ

@FlorianF यदि आप इस मामले में Awesomable<Beer>एक ठोस उपवर्ग की स्पष्ट परिभाषा के बिना मक्खी पर गुजरते हैं EstrellaGalicia, तब भी यह पैरामीटर प्रकार से बाहर निकल रहा है: मैंने इसे अभी चलाया: System.out.println("Type is: " + new Awesomable<Beer>() {}.parameterizedType());---> प्रकार है: पैरामीटाइज्डस्टफ $ बीयर
कैम्पा

6

नहीं, यह संभव नहीं है। नीचे की ओर अनुकूलता के मुद्दों के कारण, जावा की जेनेरिक टाइप इरेज़र , आईआईए रनटाइम के आधार पर , आपके पास एक गैर-जेनेरिक Listऑब्जेक्ट है। रनटाइम पर टाइप मापदंडों के बारे में कुछ जानकारी है, लेकिन यह कक्षा परिभाषाओं में रहता है (यानी आप पूछ सकते हैं " इस क्षेत्र की परिभाषा क्या सामान्य है? "), वस्तु उदाहरणों में नहीं।


हालांकि जावा इसे रनटाइम के दौरान मेटा डेटा के रूप में संग्रहीत कर सकता है, नहीं? मुझे उम्मीद थी कि यह होगा। खराब किस्मत।
cimnine

1
@ user99475: नहींं। मैं सही हूं और एंड्री गलत है। वह मेरे उत्तर के दूसरे भाग में मेरे द्वारा बताई गई प्रकार की जानकारी का उल्लेख कर रहा है, लेकिन वह वह नहीं है जो प्रश्न पूछता है।
माइकल बोर्गवर्ड

5

जैसा कि @bertolami द्वारा बताया गया है, यह हमारे लिए एक परिवर्तनीय प्रकार के लिए संभव नहीं है और इसका भविष्य मूल्य (टाइपऑफलाइन चर की सामग्री) प्राप्त करें।

फिर भी, आप इसे इस तरह से पैरामीटर के रूप में कक्षा पास कर सकते हैं:

public final class voodoo {
    public static void chill(List<T> aListWithTypeSpiderMan, Class<T> clazz) {
        // Here I'd like to get the Class-Object 'SpiderMan'
        Class typeOfTheList = clazz;
    }

    public static void main(String... args) {
        chill(new List<SpiderMan>(), Spiderman.class );
    }
}

यही कारण है कि कम या ज्यादा आप के निर्माता के लिए एक वर्ग चर पारित करने के लिए है जब गूगल करता है क्या ActivityInstrumentationTestCase2


3

नहीं, यह संभव नहीं है।

आप एक सामान्य प्रकार के क्षेत्र को प्राप्त कर सकते हैं जिसे एक वर्ग दिया गया है, जो उस नियम का एकमात्र अपवाद है और यहां तक ​​कि एक हैक का भी।

उदाहरण के लिए जावा में सामान्य प्रकार के ज्ञान को देखें ।


1

आप इस उदाहरण की तरह प्रतिबिंब के साथ एक सामान्य पैरामीटर का प्रकार प्राप्त कर सकते हैं जो मुझे यहां मिला :

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class Home<E> {
    @SuppressWarnings ("unchecked")
    public Class<E> getTypeParameterClass(){
        Type type = getClass().getGenericSuperclass();
        ParameterizedType paramType = (ParameterizedType) type;
        return (Class<E>) paramType.getActualTypeArguments()[0];
    }

    private static class StringHome extends Home<String>{}
    private static class StringBuilderHome extends Home<StringBuilder>{}
    private static class StringBufferHome extends Home<StringBuffer>{}   

    /**
     * This prints "String", "StringBuilder" and "StringBuffer"
     */
    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        Object object0 = new StringHome().getTypeParameterClass().newInstance();
        Object object1 = new StringBuilderHome().getTypeParameterClass().newInstance();
        Object object2 = new StringBufferHome().getTypeParameterClass().newInstance();
        System.out.println(object0.getClass().getSimpleName());
        System.out.println(object1.getClass().getSimpleName());
        System.out.println(object2.getClass().getSimpleName());
    }
}

V का गृह <K, V> प्राप्त करने के लिए आप कैसे काम करेंगे?
राफेल बेंच

1

जावा सामान्य प्रकार के मिटने के कारण प्रश्न का त्वरित उत्तर वह नहीं है जो आप नहीं कर सकते।

इसका उत्तर यह होगा कि यदि आपने अपनी सूची इस तरह बनाई है:

new ArrayList<SpideMan>(){}

फिर इस मामले में जेनेरिक प्रकार ऊपर के नए अनाम वर्ग के सामान्य सुपरक्लास में संरक्षित है।

ऐसा नहीं है कि मैं सूचियों के साथ ऐसा करने की सलाह देता हूं, लेकिन यह एक श्रोता कार्यान्वयन है:

new Listener<Type>() { public void doSomething(Type t){...}}

और जेवीएम के बीच सामान्य प्रकार और सुपर इंटरफेस के सामान्य प्रकारों को अतिरिक्त रूप से बदलने के बाद, जेनेरिक समाधान उतना सीधा आगे नहीं है जितना कि कुछ उत्तर सुझा सकते हैं।

यहाँ अब मैं यह किया है।


0

यह असंभव है क्योंकि जावा में जेनरिक को केवल संकलन के समय माना जाता है। इस प्रकार, जावा जेनरिक कुछ प्रकार के प्री-प्रोसेसर हैं। हालाँकि आप सूची के सदस्यों का वास्तविक वर्ग प्राप्त कर सकते हैं।


हाँ, वही अब मैं कर रहा हूँ। लेकिन अब मैं यह जानना चाहता हूं कि सूची खाली है या नहीं। लेकिन चार लोग गलत नहीं हो सकते। आप सभी को धन्यवाद)!
cimnine

19
यह सच नहीं है। जबकि यह मुश्किल है आप अगले पोस्ट में देख सकते हैं कि ParameterizedType इसे करने की अनुमति देता है।
एडमंडो १

1
सहमत, यह किया जा सकता है। DerMike का उदाहरण इसे रेखांकित करता है (मेरे लिए काम किया)।
मैक

"चार लोग गलत नहीं हो सकते हैं" पर LOL। यह उत्तर सही है।
दाऊद इब्न करीम

0

मैंने इसे उन तरीकों के लिए कोडित किया है जो स्वीकार करने या लौटने की उम्मीद करते हैं Iterable<?...>। यहाँ कोड है:

/**
 * Assuming the given method returns or takes an Iterable<T>, this determines the type T.
 * T may or may not extend WindupVertexFrame.
 */
private static Class typeOfIterable(Method method, boolean setter)
{
    Type type;
    if (setter) {
        Type[] types = method.getGenericParameterTypes();
        // The first parameter to the method expected to be Iterable<...> .
        if (types.length == 0)
            throw new IllegalArgumentException("Given method has 0 params: " + method);
        type = types[0];
    }
    else {
        type = method.getGenericReturnType();
    }

    // Now get the parametrized type of the generic.
    if (!(type instanceof ParameterizedType))
        throw new IllegalArgumentException("Given method's 1st param type is not parametrized generic: " + method);
    ParameterizedType pType = (ParameterizedType) type;
    final Type[] actualArgs = pType.getActualTypeArguments();
    if (actualArgs.length == 0)
        throw new IllegalArgumentException("Given method's 1st param type is not parametrized generic: " + method);

    Type t = actualArgs[0];
    if (t instanceof Class)
        return (Class<?>) t;

    if (t instanceof TypeVariable){
        TypeVariable tv =  (TypeVariable) actualArgs[0];
        AnnotatedType[] annotatedBounds = tv.getAnnotatedBounds();///
        GenericDeclaration genericDeclaration = tv.getGenericDeclaration();///
        return (Class) tv.getAnnotatedBounds()[0].getType();
    }

    throw new IllegalArgumentException("Unknown kind of type: " + t.getTypeName());
}

0

आप एक चर से एक सामान्य पैरामीटर प्राप्त नहीं कर सकते। लेकिन आप एक विधि या क्षेत्र घोषणा से कर सकते हैं:

Method method = getClass().getDeclaredMethod("chill", List.class);
Type[] params = method.getGenericParameterTypes();
ParameterizedType firstParam = (ParameterizedType) params[0];
Type[] paramsOfFirstGeneric = firstParam.getActualTypeArguments();

यह मुझे थ्रेड में एक अपवाद देता है "मुख्य" java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl
मार्टिनेज

'params' 'प्रकार' है जिसमें कई उप-केंद्र हैं। TypeVariableImpl वह है जो विधि तर्कों के लिए उपयोग किया जाता है और यह <> s के अंदर जेनेरिक का नाम बताता है, न कि उस वर्ग का जो इसका प्रतिनिधित्व करता है।
ली मीडोर

0

मेरे लिए कोड के इस स्निपेट को पढ़ना कठिन था, मैंने इसे केवल 2 पठनीय रेखाओं में विभाजित किया:

// assuming that the Generic Type parameter is of type "T"
ParameterizedType p = (ParameterizedType) getClass().getGenericSuperclass();
Class<T> c =(Class<T>)p.getActualTypeArguments()[0];

मैं अपनी पद्धति का कोई भी पैरामीटर न रखते हुए टाइप पैरामीटर का एक उदाहरण बनाना चाहता था:

publc T getNewTypeInstance(){
    ParameterizedType p = (ParameterizedType) getClass().getGenericSuperclass();
    Class<T> c =(Class<T>)p.getActualTypeArguments()[0];

    // for me i wanted to get the type to create an instance
    // from the no-args default constructor
    T t = null;
    try{
        t = c.newInstance();
    }catch(Exception e){
        // no default constructor available
    }
    return t;
}

0

यहाँ एक और चाल है। जेनेरिक वैरग सरणी का उपयोग करें

import java.util.ArrayList;

class TypedArrayList<E> extends ArrayList<E>
{
    @SafeVarargs
    public TypedArrayList (E... typeInfo)
    {
        // Get generic type at runtime ...
        System.out.println (typeInfo.getClass().getComponentType().getTypeName());
    }
}

public class GenericTest
{
    public static void main (String[] args)
    {
        // No need to supply the dummy argument
        ArrayList<Integer> ar1 = new TypedArrayList<> ();
        ArrayList<String> ar2 = new TypedArrayList<> ();
        ArrayList<?> ar3 = new TypedArrayList<> ();
    }
}

0

मैंने देखा कि बहुत से लोग getGenericSuperclass()समाधान की ओर झुकते हैं:

class RootGeneric<T> {
  public Class<T> persistentClass = (Class<T>)
    ((ParameterizedType)getClass().getGenericSuperclass())
      .getActualTypeArguments()[0];
}

हालाँकि, यह समाधान त्रुटि प्रवण है। अगर वंशजों में उदारता है तो यह ठीक से काम नहीं करेगा । इस पर विचार करो:

class Foo<S> extends RootGeneric<Integer> {}

class Bar extends Foo<Double> {}

किस प्रकार का होगा Bar.persistentClass? Class<Integer>? नहीं, यह होगा Class<Double>। यह getClass()हमेशा सबसे शीर्ष वर्ग के रिटर्न के कारण होगा , जो Barइस मामले में है, और इसका सामान्य सुपर क्लास है Foo<Double>। इसलिए, तर्क प्रकार होगा Double

यदि आपको एक विश्वसनीय समाधान की आवश्यकता है जो विफल नहीं होता है तो मैं दो सुझाव दे सकता हूं।

  1. का उपयोग करें Guava। यह एक वर्ग है जो इस उद्देश्य के लिए बिल्कुल बनाया गया था com.google.common.reflect.TypeToken:। यह ठीक कोने के सभी मामलों को संभालता है और कुछ और अच्छी कार्यक्षमता प्रदान करता है। नकारात्मक पक्ष एक अतिरिक्त निर्भरता है। यह देखते हुए कि आपने इस वर्ग का उपयोग किया है, आपका कोड इस तरह सरल और स्पष्ट दिखाई देगा:
class RootGeneric<T> {
  @SuppressWarnings("unchecked")
  public final Class<T> persistentClass = (Class<T>) (new TypeToken<T>(getClass()) {}.getType());
}
  1. नीचे कस्टम विधि का उपयोग करें। यह ऊपर बताए गए अमरूद वर्ग के समान एक काफी सरल तर्क को लागू करता है। हालाँकि, मैं यह गारंटी नहीं दूँगा कि यह त्रुटि प्रवण है। हालांकि यह जेनेरिक वंश के साथ समस्या को हल करता है।
abstract class RootGeneric<T> {
  @SuppressWarnings("unchecked")
  private Class<T> getTypeOfT() {
    Class<T> type = null;
    Class<?> iter = getClass();
    while (iter.getSuperclass() != null) {
      Class<?> next = iter.getSuperclass();
      if (next != null && next.isAssignableFrom(RootGeneric.class)) {
        type =
            (Class<T>)
                ((ParameterizedType) iter.getGenericSuperclass()).getActualTypeArguments()[0];
        break;
      }
      iter = next;
    }
    if (type == null) {
      throw new ClassCastException("Cannot determine type of T");
    }
    return type;
  }
}

-1

उपयोग:

Class<?> typeOfTheList = aListWithTypeSpiderMan.toArray().getClass().getComponentType();

ये गलत है। toArray()लौटता है Object[]। आप कुछ विशेष उपप्रकार होने पर निर्भर नहीं हो सकते हैं और नहीं होना चाहिए।
रेडियोडेफ़
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.