रनटाइम के दौरान सामान्य प्रकार की क्लास लें


508

इसे कैसे प्राप्त किया जा सकता है?

public class GenericClass<T>
{
    public Type getMyType()
    {
        //How do I return the type of T?
    }
}

मैंने अब तक जो कुछ भी आजमाया है वह हमेशा Objectउपयोग किए जाने वाले विशिष्ट प्रकार के बजाय हमेशा रिटर्न टाइप करता है।


3
@SamuelVidal यह .NET नहीं है, यह जावा है।
फ्रंटियर

जवाबों:


317

जैसा कि दूसरों ने उल्लेख किया है, यह केवल कुछ परिस्थितियों में प्रतिबिंब के माध्यम से संभव है।

यदि आपको वास्तव में प्रकार की आवश्यकता है, तो यह सामान्य (टाइप-सेफ) वर्कअराउंड पैटर्न है:

public class GenericClass<T> {

     private final Class<T> type;

     public GenericClass(Class<T> type) {
          this.type = type;
     }

     public Class<T> getMyType() {
         return this.type;
     }
}

58
मुझे यह उत्तर पसंद है लेकिन यह तात्कालिकता के लिए थोड़ा बोझिल है: GenericClass <OtherClass> g = new GenericClass <OtherClass> (अन्यClass.class);
एलिसा ओसेम्पोस

1
यदि आप एक डाओ / कारखाने / प्रबंधक दृष्टिकोण का उपयोग करते हैं तो यह और भी अधिक क्रिया है। Foo foo1 = GetDao<Foo>(Foo.class).get(Foo.class, 1)
djmj

2
यह सच है, लेकिन सभी मामलों में काम नहीं कर रहा जैसे स्टेटलेस रिमोट बीन्स जो कि कंटेनर / रिफ्लेक्ट द्वारा तुरंत किए जाते हैं।
djmj

6
बस मेरी पिछली टिप्पणी के अनुवर्ती के रूप में - बहुत दर्द के बाद प्रतिबिंब के साथ खेलना, मैंने इस उत्तर का उपयोग करके समाप्त कर दिया।
टॉम ज़ातो - मोनिका

18
आप सामान्य स्टेटिक फ़ैक्टरी विधि प्रदान करके शानदार संदर्भ प्राप्त कर सकते हैं। की तरह कुछ public static <T> GenericClass<T> of(Class<T> type) {...}और उसके बाद इस तरह के रूप में यह कहते हैं: GenericClass<String> var = GenericClass.of(String.class)। थोड़ा सा अच्छा।
जोएरी हेंड्रिकक्स

262

मैंने ऐसा कुछ देखा है

private Class<T> persistentClass;

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

में हाइबरनेट GenericDataAccessObjects उदाहरण


84
यह तकनीक काम करती है जहां टाइप पैरामीटर को तत्काल सुपरक्लास पर परिभाषित किया गया है, लेकिन यह विफल रहता है यदि टाइप पैरामीटर को पदानुक्रम में कहीं और परिभाषित किया गया है। अधिक जटिल मामलों को संभालने के लिए टाइपटूल्स जैसे कुछ का उपयोग किया जा सकता है। डॉक्स में अधिक परिष्कृत जेनेरिक DAO का उदाहरण शामिल है।
जोनाथन

25
यह केवल वास्तविक प्रकार के मापदंडों का उपयोग करता है जब एक CLASS लागू होता है / कुछ ऐसा करता है जिसमें सामान्य घोषणाएँ होती हैं, यह तब वास्तविक प्रकार के मापदंडों का उपयोग नहीं करता है जब एक INSTANCE त्वरित किया जाता है। दूसरे शब्दों में, यह बता सकता है कि class A implements Comparable<String>वास्तविक प्रकार पैरामीटर है String, लेकिन यह नहीं बता सकता है कि Set<String> a = new TreeSet<String>()वास्तविक प्रकार पैरामीटर है String। वास्तव में, टाइप पैरामीटर जानकारी संकलन के बाद "मिटा" है, जैसा कि अन्य उत्तरों में समझाया गया है।
सियु चिंग पोंग -आसुका केंजी-

32
मुझे java.lang.Class cannot be cast to java.lang.reflect.ParameterizedTypeइसका जवाब मिल रहा है ।
टॉम ज़ातो - मोनिका

4
यह दृष्टिकोण Class-Mateजैक्सन के लोगों से भी प्राप्त किया जा सकता है । मैंने यहाँ एक gist लिखा है। gith.github.com/yunspace/930d4d40a787a1f6a7d1
yunspace

5
@ TomášZato कॉलिंग बस ऊपर दिए गए कोड ने मेरे लिए एक ही अपवाद लौटा दिया। मुझे पता है कि थोड़ी देर हो चुकी है, लेकिन वैसे भी, मेरे मामले में, मुझे (Class<T>) ((ParameterizedType)getClass().getSuperclass().getGenericSuperclass()).getActualTypeArguments()वास्तविक प्रकार के तर्क प्राप्त करने के लिए कॉल करना था ।
एंड्रयू मैककोस्टिस्ट

98

रन-टाइम पर जेनेरिकों का पुनरीक्षण नहीं किया जाता है। इसका मतलब है कि सूचना रन-टाइम पर मौजूद नहीं है।

जावा में जेनेरिक को जोड़ना जबकि पिछड़ेपन को बनाए रखना एक टूर-डे-फोर्स था (आप इसके बारे में सेमिनल पेपर देख सकते हैं: भविष्य को अतीत के लिए सुरक्षित बनाना: जावा प्रोग्रामिंग भाषा में उदारता जोड़ना )।

इस विषय पर एक समृद्ध साहित्य है, और कुछ लोग वर्तमान स्थिति से असंतुष्ट हैं , कुछ कहते हैं कि वास्तव में यह एक आकर्षण है और इसके लिए कोई वास्तविक आवश्यकता नहीं है। आप दोनों लिंक पढ़ सकते हैं, मैंने उन्हें काफी दिलचस्प पाया।


179
बेशक, हम असंतुष्ट हैं। .NET में बेहतर बेहतर हैंडलिंग तंत्र है
Pacerier

6
@ स्पेसर: लेकिन केवल सामान्यीकृत जेनेटिक्स जावा को .NET के स्तर पर नहीं लाएगा। मानों के लिए एक विशेष कोड उन लोगों के लिए कम से कम उतना ही महत्वपूर्ण है कि क्यों जेनेटिक्स क्षेत्र में .NET बेहतर है।
जोकिम सॉयर

@ जोचिमसाउर, हाँ मूल्य प्रकार। मैं हमेशा उन जावा में चाहता था। Btw आप विशेष कोड से क्या मतलब है?
पचेरियर

3
@ Spaaarky21 नहीं, सामान्य प्रकार के मापदंडों को संकलन के दौरान हटा दिया जाता है (तथाकथित "इरेज़र", आप इसे Google कर सकते हैं)। FrVaBe के उत्तर में ट्रिक केवल तभी काम करती है जब सुपरक्लास के टाइप पैरामेट्स को स्टेटिक रूप से जाना जाता है (जॉनाथन द्वारा पहला कमिशन देखें)
ewernli

1
जावा प्रकार का क्षरण एक ऐतिहासिक डिजाइन दोष है; इसे लागू करने के लिए जितना लिखा गया था उससे अधिक कोड इसके चारों ओर पाने के लिए लिखा गया है।
अभिजीत सरकार

68

अमरूद का उपयोग करें।

import com.google.common.reflect.TypeToken;
import java.lang.reflect.Type;

public abstract class GenericClass<T> {
  private final TypeToken<T> typeToken = new TypeToken<T>(getClass()) { };
  private final Type type = typeToken.getType(); // or getRawType() to return Class<? super T>

  public Type getType() {
    return type;
  }

  public static void main(String[] args) {
    GenericClass<String> example = new GenericClass<String>() { };
    System.out.println(example.getType()); // => class java.lang.String
  }
}

कुछ समय पहले, मैंने सार वर्ग और उपवर्ग सहित कुछ पूर्ण-उदाहरण दिए हैं

नोट: इसके लिए यह आवश्यक है कि आप एक उपवर्ग को तुरंत GenericClassटाइप करें ताकि यह टाइप पैरामीटर को सही ढंग से बाँध सके। अन्यथा यह बस के रूप में वापस आ जाएगी T


3
ध्यान दें कि मैं एक खाली अनाम उपवर्ग बनाता हूं (अंत में दो घुंघराले ब्रेसिज़ देखें)। यह जावा के रनटाइम प्रकार को मिटाने के लिए प्रतिबिंब का उपयोग करता है। आप यहाँ और अधिक सीख सकते हैं: code.google.com/p/guava-lbooks/wiki/ReflectionExplained
कोडी ए। रे।

3
@ कोडी। आपका कोड फेंकता है a java.lang.IllegalArgumentException: class com.google.common.reflect.TypeToken isn't parameterized। इसलिए मैंने लाइन new TypeToken(getClass()) { }को बदल दिया new TypeToken<T>(getClass()) { }। अब, कोड ठीक चलता है, लेकिन टाइप अभी भी 'T' है। इसे देखें: gist.github.com/m-manu/9cda9d8f9d53bead2035
Manu Manjunath

3
@Dominik कृपया अद्यतन उदाहरण देखें जिसे आप कॉपी और पेस्ट कर सकते हैं अपने आप को परीक्षण करने के लिए। मैंने एक नोट भी जोड़ा है जिसमें स्पष्ट किया गया है कि आपको एक उपवर्ग (जैसा कि दिखाया गया है) तुरंत भेजना चाहिए। एक सामान्य शिष्टाचार सलाह के रूप में, "इच्छाधारी सोच" के पोस्टर पर आरोप लगाने से पहले कृपया किसी भी लिंक किए गए लेख और संबंधित javadocs पढ़ें। मैंने कई बार समान उत्पादन कोड का उपयोग किया है। मैं जिन अमरूद सहायकों का प्रदर्शन कर रहा हूं, वे इस सटीक उपयोग के मामले में हैं और उनके javadocs इस प्रश्न का लगभग सटीक उत्तर दिखाते हैं। docs.guava-lbooks.googlecode.com/git/javadoc/com/google/…
Cody A. Ray

1
यह उत्तर जावा 8 के साथ बहुत अच्छा काम करता है - मेरे पास विभिन्न प्रकारों का उत्सर्जन करने के लिए एक इंटरफ़ेस और एक कारखाना वर्ग है, और चाहते थे कि उपयोगकर्ता आसानी से प्रकार का निर्धारण करने में सक्षम हों। अपने इंटरफ़ेस में मैंने डिफ़ॉल्ट तरीका जोड़ा: default Type getParameterType() { final TypeToken<T> typeToken = new TypeToken<T>(getClass()) {}; final Type type = typeToken.getType(); return type; }
रिचर्ड सैंड

2
@ CodyA.Ray चूंकि यह केवल उपवर्गों के साथ काम करता है GenericClass, इसलिए आपको उस वर्ग को abstractगलत उपयोग करने के लिए तैयार नहीं करना चाहिए।
मार्टिन

37

जरूर आप कर सकते हो।

जावा रन टाइम पर जानकारी का उपयोग नहीं करता है , पश्चगामी संगतता कारणों के लिए। लेकिन जानकारी वास्तव में मौजूद है में मेटाडेटा के रूप है और इसे प्रतिबिंब के माध्यम से एक्सेस किया जा सकता है (लेकिन यह अभी भी टाइप-चेकिंग के लिए उपयोग नहीं किया जाता है)।

आधिकारिक एपीआई से:

http://download.oracle.com/javase/6/docs/api/java/lang/reflect/ParameterizedType.html#getActualTypeArguments%28%29

हालाँकि , आपके परिदृश्य के लिए, मैं प्रतिबिंब का उपयोग नहीं करूंगा। मैं व्यक्तिगत रूप से फ्रेमवर्क कोड के लिए इसका उपयोग करने के लिए इच्छुक हूं। आपके मामले में मैं सिर्फ एक निर्माता के रूप में टाइप करूँगा।


10
getActualTypeArguments केवल तत्काल वर्ग के लिए प्रकार तर्क देता है। यदि आपके पास एक जटिल प्रकार की पदानुक्रम है जहां टी को पदानुक्रम में कहीं भी पैरामीटर किया जा सकता है, तो आपको यह पता लगाने के लिए थोड़ा काम करना होगा कि यह क्या है। यह कमोबेश TypeTools क्या करता है।
जोनाथन

36

जावा जेनरिक ज्यादातर संकलित समय है, इसका मतलब यह है कि रनटाइम में टाइप जानकारी खो जाती है।

class GenericCls<T>
{
    T t;
}

कुछ इस तरह संकलित किया जाएगा

class GenericCls
{
   Object o;
}

रनटाइम पर प्रकार की जानकारी प्राप्त करने के लिए आपको इसे ctor के तर्क के रूप में जोड़ना होगा।

class GenericCls<T>
{
     private Class<T> type;
     public GenericCls(Class<T> cls)
     {
        type= cls;
     }
     Class<T> getType(){return type;}
}

उदाहरण:

GenericCls<?> instance = new GenericCls<String>(String.class);
assert instance.getType() == String.class;

9
private final Class<T> type;
naXa

मैं इससे एक सरणी प्रकार कैसे बना सकता हूं:Type t = //String[]
पावेल कियोच

@PawelCioch java.lang.reflect.Array.newInstance (एलिमेंटाइप, लंबाई); आशा है कि यह मदद करता है (javadoc यहाँ पाया जा सकता है docs.oracle.com/javase/8/docs/api/java/lang/reflect/… )
josefx

@PawelCioch निर्मित सरणी से प्रकार प्राप्त करने के लिए .getClass () से चूक गया। एक सरणी वर्ग प्राप्त करने का एक सीधा तरीका प्रतीत नहीं होता है। अधिकांश जावा संग्रह केवल ऑब्जेक्ट [] का उपयोग करते हैं।
josefx

23
public abstract class AbstractDao<T>
{
    private final Class<T> persistentClass;

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

3
मैं इस जवाब को बढ़ा रहा हूं क्योंकि यह एक समाधान है जो पूछे जाने वाले प्रश्न के लिए काम करता है। हालाँकि, जो लोग एक से अधिक जेनेरिक क्लास के साथ खुद की तरह वर्ग पदानुक्रम में ऊपर की ओर नेविगेट करना चाहते हैं, उनके लिए यह काम नहीं करेगा। क्योंकि आपको वास्तविक वर्ग के बजाय java.lang.object मिलेगा।
केएमसी

3
कृपया ध्यान दें कि यह समाधान केवल तभी काम करता है यदि जेनेरिक प्रकार रखने वाला वर्ग ABSTRACT है
बाबैन्यूव्यू

जावा 11 में मेरे सार वर्ग के साथ काम नहीं किया
JRA_TLL

@JRA_TLL आपने स्पष्ट रूप से कुछ गलत किया है। मैंने इसे केवल जावा 12 के साथ इस्तेमाल किया और एक आकर्षण की तरह काम करता है।
गोगोई

यदि आप पदानुक्रम को ध्यान में रखते हुए नेविगेट करना चाहते हैं, तो आप जेनेरिकसुपरक्लास को कक्षा <*> में डाल सकते हैं और जेनेरिकसुपरक्लास प्राप्त कर सकते हैं। अधिमानतः एक लूप में।
फूपदुक

21

मैंने निम्नलिखित दृष्टिकोण का उपयोग किया:

public class A<T> {

    protected Class<T> clazz;

    public A() {
        this.clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

    public Class<T> getClazz() {
        return clazz;
    }
}

public class B extends A<C> {
   /* ... */
    public void anything() {
       // here I may use getClazz();
    }
}

9
मुझे "थ्रेड में अपवाद" मुख्य "java.lang.ClassCastException: java.lang.Class इस नमूना कोड के साथ java.lang.reflect.ParameterizedType पर नहीं डाला जा सकता है
यमंग

16

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

ओरेकल डॉक्स से:

इरेज़र टाइप करें

संकलन समय पर तंग प्रकार की जांच प्रदान करने और सामान्य प्रोग्रामिंग का समर्थन करने के लिए जावा भाषा में जेनरिक की शुरुआत की गई। जेनेरिक को लागू करने के लिए, जावा कंपाइलर निम्न प्रकार पर लागू होता है:

सभी प्रकार के मापदंडों को जेनेरिक प्रकारों में उनकी सीमा या ऑब्जेक्ट के साथ बदलें यदि प्रकार पैरामीटर अनबाउंड हैं। इसलिए, उत्पादित बायोटेक में केवल सामान्य वर्ग, इंटरफेस और विधियां शामिल हैं। यदि आवश्यक हो तो टाइप सेफ्टी को सुरक्षित रखने के लिए टाइप कास्ट डालें। विस्तारित सामान्य प्रकारों में बहुरूपता को संरक्षित करने के लिए सेतु विधियाँ उत्पन्न करें। प्रकार का क्षरण यह सुनिश्चित करता है कि पैरामीटर प्रकारों के लिए कोई नई कक्षाएं नहीं बनाई गई हैं; नतीजतन, जेनरिक कोई रनटाइम ओवरहेड नहीं है।

http://docs.oracle.com/javase/tutorial/java/generics/erasure.html


बृहस्पति, यह असंभव है। जावा को काम करने के लिए सामान्यीकृत पुनरीक्षण की आवश्यकता होगी।
हेनिंग

15

इयान रॉबर्टसन के इस लेख में वर्णित तकनीक मेरे लिए काम करती है।

कम त्वरित और गंदे उदाहरण में:

 public abstract class AbstractDAO<T extends EntityInterface, U extends QueryCriteria, V>
 {
    /**
     * Method returns class implementing EntityInterface which was used in class
     * extending AbstractDAO
     *
     * @return Class<T extends EntityInterface>
     */
    public Class<T> returnedClass()
    {
        return (Class<T>) getTypeArguments(AbstractDAO.class, getClass()).get(0);
    }

    /**
     * Get the underlying class for a type, or null if the type is a variable
     * type.
     *
     * @param type the type
     * @return the underlying class
     */
    public static Class<?> getClass(Type type)
    {
        if (type instanceof Class) {
            return (Class) type;
        } else if (type instanceof ParameterizedType) {
            return getClass(((ParameterizedType) type).getRawType());
        } else if (type instanceof GenericArrayType) {
            Type componentType = ((GenericArrayType) type).getGenericComponentType();
            Class<?> componentClass = getClass(componentType);
            if (componentClass != null) {
                return Array.newInstance(componentClass, 0).getClass();
            } else {
                return null;
            }
        } else {
            return null;
        }
    }

    /**
     * Get the actual type arguments a child class has used to extend a generic
     * base class.
     *
     * @param baseClass the base class
     * @param childClass the child class
     * @return a list of the raw classes for the actual type arguments.
     */
    public static <T> List<Class<?>> getTypeArguments(
            Class<T> baseClass, Class<? extends T> childClass)
    {
        Map<Type, Type> resolvedTypes = new HashMap<Type, Type>();
        Type type = childClass;
        // start walking up the inheritance hierarchy until we hit baseClass
        while (!getClass(type).equals(baseClass)) {
            if (type instanceof Class) {
                // there is no useful information for us in raw types, so just keep going.
                type = ((Class) type).getGenericSuperclass();
            } else {
                ParameterizedType parameterizedType = (ParameterizedType) type;
                Class<?> rawType = (Class) parameterizedType.getRawType();

                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                TypeVariable<?>[] typeParameters = rawType.getTypeParameters();
                for (int i = 0; i < actualTypeArguments.length; i++) {
                    resolvedTypes.put(typeParameters[i], actualTypeArguments[i]);
                }

                if (!rawType.equals(baseClass)) {
                    type = rawType.getGenericSuperclass();
                }
            }
        }

        // finally, for each actual type argument provided to baseClass, determine (if possible)
        // the raw class for that type argument.
        Type[] actualTypeArguments;
        if (type instanceof Class) {
            actualTypeArguments = ((Class) type).getTypeParameters();
        } else {
            actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
        }
        List<Class<?>> typeArgumentsAsClasses = new ArrayList<Class<?>>();
        // resolve types by chasing down type variables.
        for (Type baseType : actualTypeArguments) {
            while (resolvedTypes.containsKey(baseType)) {
                baseType = resolvedTypes.get(baseType);
            }
            typeArgumentsAsClasses.add(getClass(baseType));
        }
        return typeArgumentsAsClasses;
    }
  }

3
इस कोड में किस विशिष्ट लाइन पर वास्तविक, रन-टाइम टाइप पैरामीटर पढ़ा जा रहा है?
इवान मटवुलज

यहाँ? Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
ओन्ड्रेज बोजेक

9

मुझे लगता है कि एक और सुरुचिपूर्ण समाधान है।

आप क्या करना चाहते हैं (सुरक्षित रूप से) "पास" जेनेरिक प्रकार के पैरामीटर का प्रकार जो कंकरीट क्लास से सुपरक्लास तक है।

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

पहले इन पंक्तियों के साथ एक कस्टम एनोटेशन परिभाषित करें:

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EntityAnnotation {
    Class entityClass();
}

फिर आपको अपने उपवर्ग में एनोटेशन जोड़ना होगा।

@EntityAnnotation(entityClass =  PassedGenericType.class)
public class Subclass<PassedGenericType> {...}

तब आप अपने बेस क्लास में क्लास टाइप पाने के लिए इस कोड का उपयोग कर सकते हैं:

import org.springframework.core.annotation.AnnotationUtils;
.
.
.

private Class getGenericParameterType() {
    final Class aClass = this.getClass();
    EntityAnnotation ne = 
         AnnotationUtils.findAnnotation(aClass, EntityAnnotation.class);

    return ne.entityClass();
}

इस दृष्टिकोण की कुछ सीमाएँ हैं:

  1. आप सामान्य प्रकार निर्दिष्ट करें (PassedGenericType दो-दो स्थानों पर ) हैं जो एक गैर-डीआरवाई है।
  2. यह तभी संभव है जब आप ठोस उपवर्गों को संशोधित कर सकते हैं।

हां, यह गैर-डीआरवाई है, हालांकि यह ऊपर दिए गए विस्तार दृष्टिकोण से साफ है। मुझे अच्छा लगा। धन्यवाद
agodinhost

8

यह मेरा समाधान है:

import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;

public class GenericClass<T extends String> {

  public static void main(String[] args) {
     for (TypeVariable typeParam : GenericClass.class.getTypeParameters()) {
      System.out.println(typeParam.getName());
      for (Type bound : typeParam.getBounds()) {
         System.out.println(bound);
      }
    }
  }
}

10
यह इस सवाल का जवाब नहीं है।
एडम एरॉल्ड

1
मेरा कोड प्रश्न के लिए सटीक समाधान नहीं है। यह कक्षा के सामान्य प्रकार के मापदंडों को लौटाता है, लेकिन वास्तविक प्रकार के टी को नहीं। लेकिन यह उन लोगों के लिए मददगार हो सकता है जो सवाल पर डगमगाते हैं और मेरे समाधान की तलाश में हैं।
मथायस एम

1
getClass () .GGenericSuperclass () समान प्रभाव प्राप्त करेगा।
गोर्की

5

यहाँ काम कर रहा है समाधान !!!

@SuppressWarnings("unchecked")
    private Class<T> getGenericTypeClass() {
        try {
            String className = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName();
            Class<?> clazz = Class.forName(className);
            return (Class<T>) clazz;
        } catch (Exception e) {
            throw new IllegalStateException("Class is not parametrized with generic type!!! Please use extends <> ");
        }
    } 

नोट: केवल सुपरक्लास के रूप में इस्तेमाल किया जा सकता है
1. टाइप क्लास के साथ बढ़ाया जाना है ( Child extends Generic<Integer>)
या

2. कार्यान्वयन के रूप में बनाया जाना है ( new Generic<Integer>() {};)


4

आप नहीं कर सकते। यदि आप वर्ग में टाइप T के सदस्य चर को जोड़ते हैं (आपको इसे इनिशियलाइज़ भी नहीं करना है), तो आप उस प्रकार को पुनर्प्राप्त करने के लिए उपयोग कर सकते हैं।


2
उफ़, ठीक है। आप करते हैं एक निर्माता से आरंभ करने के लिए है।
andrewmu

4

यहां एक तरीका है, जिसे मुझे एक या दो बार उपयोग करना है:

public abstract class GenericClass<T>{
    public abstract Class<T> getMyType();
}

साथ में

public class SpecificClass extends GenericClass<String>{

    @Override
    public Class<String> getMyType(){
        return String.class;
    }
}

4
यह तकनीकी रूप से काम करता है, हालांकि यह सामान्य मामले को हल नहीं करता है, और मुझे लगता है कि मूल पोस्टर के बाद क्या है।
ggb667 15

यह इस तरह से वोट देने के लायक नहीं है जैसे मूल पोस्टर में स्पष्ट नहीं किया गया है। यह उत्तर एक डिज़ाइन पैटर्न प्रदान करता है जो काम करता है और इसे लागू करना आसान है, बशर्ते कि यह सामान्य वर्ग को सार बनाने के लिए उपयुक्त है।
VirtualMichael

4

इस टैक्सी के लिए एक सरल समाधान नीचे की तरह होना चाहिए

public class GenericDemo<T>{
    private T type;

    GenericDemo(T t)
    {
        this.type = t;
    }

    public String getType()
    {
        return this.type.getClass().getName();
    }

    public static void main(String[] args)
    {
        GenericDemo<Integer> obj = new  GenericDemo<Integer>(5);
        System.out.println("Type: "+ obj.getType());
    }
}

3

यहाँ कुछ उत्तरों को पूरा करने के लिए, मुझे MyGenericClass का ParametrizedType प्राप्त करना था, भले ही पुनरावृत्ति की सहायता से पदानुक्रम कितना अधिक हो:

private Class<T> getGenericTypeClass() {
        return (Class<T>) (getParametrizedType(getClass())).getActualTypeArguments()[0];
}

private static ParameterizedType getParametrizedType(Class clazz){
    if(clazz.getSuperclass().equals(MyGenericClass.class)){ // check that we are at the top of the hierarchy
        return (ParameterizedType) clazz.getGenericSuperclass();
    } else {
        return getParametrizedType(clazz.getSuperclass());
    }
}

1

यहाँ मेरी चाल है:

public class Main {

    public static void main(String[] args) throws Exception {

        System.out.println(Main.<String> getClazz());

    }

    static <T> Class getClazz(T... param) {

        return param.getClass().getComponentType();
    }

}

1
नोट: यह तब काम नहीं करता है जब Tएक प्रकार का चर है। इस Tप्रकार के मामले में , एक प्रकार का परिवर्तनशील है, varargs के मिटने की एक सरणी बनाता है T। जैसे देखें http://ideone.com/DIPNwd
रेडियोएडफ़

1
यह "वस्तु"
यज्ञ

हो सकता है कि आप किसी अन्य प्रश्न का उत्तर देने की कोशिश कर रहे हों you're
खान

1

यदि आप जेनेरिक प्रकार का उपयोग करके एक चर का उपयोग करते हैं तो बस आप इस समस्या को आसानी से हल कर सकते हैं।

public class Constant<T> {
  private T value;

  @SuppressWarnings("unchecked")
  public Class<T> getClassType () {
    return ((Class<T>) value.getClass());
  }
}

मैं दिए गए वर्ग वस्तु का उपयोग बाद में यह जांचने के लिए करता हूं कि यह किसी दिए गए वर्ग का उदाहरण है या नहीं, इस प्रकार है:

Constant<?> constant = ...;
if (constant.getClassType().equals(Integer.class)) {
    Constant<Integer> integerConstant = (Constant<Integer>)constant;
    Integer value = integerConstant.getValue();
    // ...
}

2
यह दुर्भाग्यपूर्ण है। सबसे पहले, यदि क्या valueहै null? सब से दूसरा, क्या होगा यदि valueउपवर्ग है T? जब लौटना चाहिए तब Constant<Number> c = new Constant<Number>(new Integer(0)); Class<Number> n = c.getClassType();लौटता है । लौटना अधिक सही होगा । एक है, लेकिन नहीं है । Integer.classNumber.classClass<? extends T>Integer.class Class<? extends Number>Class<Number>
रेडिओडफ

1

यहाँ मेरा समाधान है

public class GenericClass<T>
{
    private Class<T> realType;

    public GenericClass() {
        findTypeArguments(getClass());
    }

    private void findTypeArguments(Type t) {
        if (t instanceof ParameterizedType) {
            Type[] typeArgs = ((ParameterizedType) t).getActualTypeArguments();
            realType = (Class<T>) typeArgs[0];
        } else {
            Class c = (Class) t;
            findTypeArguments(c.getGenericSuperclass());
        }
    }

    public Type getMyType()
    {
        // How do I return the type of T? (your question)
        return realType;
    }
}

कोई फर्क नहीं पड़ता कि आपके वर्ग पदानुक्रम में कितने स्तर हैं, यह समाधान अभी भी काम करता है, उदाहरण के लिए:

public class FirstLevelChild<T> extends GenericClass<T> {

}

public class SecondLevelChild extends FirstLevelChild<String> {

}

इस स्थिति में, getMyType () = java.lang.String


यह T का प्रकार नहीं लौटा रहा है। यह T नहीं java.lang लौटा रहा है। इसके अलावा कोड को टाइप करने में असफल हो रहा है Type to Class <T>
Mohy Eldeen

यहाँ एक ऑनलाइन नमूना है जो मैंने बनाया है। संकलित करें और निष्पादित करें पर क्लिक करें, फिर आप परिणाम प्राप्त कर सकते हैं। tutorialspoint.com/…
लिन यू चेंग

मेरे लिए काम करता है - जब वाइल्डली वेल्ड सीडीआई ने एक वैकल्पिक तरीका तोड़ा।
आंद्रे

मुझे मिल गयाException in thread "main" java.lang.NullPointerException at Main$ClassA.findTypeArguments(Main.java:54) at Main$ClassA.findTypeArguments(Main.java:54) at Main$ClassA.findTypeArguments(Main.java:54) at Main$ClassA.<init>(Main.java:43) at Main.main(Main.java:61)
युएंग

0
public static final Class<?> getGenericArgument(final Class<?> clazz)
{
    return (Class<?>) ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[0];
}

0

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

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.HashMap;
import java.util.Map;

public class TypeUtils {

    /*** EXAMPLES ***/

    public static class Class1<A, B, C> {

        public A someA;
        public B someB;
        public C someC;

        public Class<?> getAType() {
            return getTypeParameterType(this.getClass(), Class1.class, 0);
        }

        public Class<?> getCType() {
            return getTypeParameterType(this.getClass(), Class1.class, 2);
        }
    }

    public static class Class2<D, A, B, E, C> extends Class1<A, B, C> {

        public B someB;
        public D someD;
        public E someE;
    }

    public static class Class3<E, C> extends Class2<String, Integer, Double, E, C> {

        public E someE;
    }

    public static class Class4 extends Class3<Boolean, Long> {

    }

    public static void test() throws NoSuchFieldException {

        Class4 class4 = new Class4();
        Class<?> typeA = class4.getAType(); // typeA = Integer
        Class<?> typeC = class4.getCType(); // typeC = Long

        Field fieldSomeA = class4.getClass().getField("someA");
        Class<?> typeSomeA = TypeUtils.getFieldType(class4.getClass(), fieldSomeA); // typeSomeA = Integer

        Field fieldSomeE = class4.getClass().getField("someE");
        Class<?> typeSomeE = TypeUtils.getFieldType(class4.getClass(), fieldSomeE); // typeSomeE = Boolean


    }

    /*** UTILS ***/

    public static Class<?> getTypeVariableType(Class<?> subClass, TypeVariable<?> typeVariable) {
        Map<TypeVariable<?>, Type> subMap = new HashMap<>();
        Class<?> superClass;
        while ((superClass = subClass.getSuperclass()) != null) {

            Map<TypeVariable<?>, Type> superMap = new HashMap<>();
            Type superGeneric = subClass.getGenericSuperclass();
            if (superGeneric instanceof ParameterizedType) {

                TypeVariable<?>[] typeParams = superClass.getTypeParameters();
                Type[] actualTypeArgs = ((ParameterizedType) superGeneric).getActualTypeArguments();

                for (int i = 0; i < typeParams.length; i++) {
                    Type actualType = actualTypeArgs[i];
                    if (actualType instanceof TypeVariable) {
                        actualType = subMap.get(actualType);
                    }
                    if (typeVariable == typeParams[i]) return (Class<?>) actualType;
                    superMap.put(typeParams[i], actualType);
                }
            }
            subClass = superClass;
            subMap = superMap;
        }
        return null;
    }

    public static Class<?> getTypeParameterType(Class<?> subClass, Class<?> superClass, int typeParameterIndex) {
        return TypeUtils.getTypeVariableType(subClass, superClass.getTypeParameters()[typeParameterIndex]);
    }

    public static Class<?> getFieldType(Class<?> clazz, AccessibleObject element) {
        Class<?> type = null;
        Type genericType = null;

        if (element instanceof Field) {
            type = ((Field) element).getType();
            genericType = ((Field) element).getGenericType();
        } else if (element instanceof Method) {
            type = ((Method) element).getReturnType();
            genericType = ((Method) element).getGenericReturnType();
        }

        if (genericType instanceof TypeVariable) {
            Class<?> typeVariableType = TypeUtils.getTypeVariableType(clazz, (TypeVariable) genericType);
            if (typeVariableType != null) {
                type = typeVariableType;
            }
        }

        return type;
    }

}

-1

मैंने @Moesio उपरोक्त के समान ही किया लेकिन कोटलिन में इसे इस प्रकार किया जा सकता है:

class A<T : SomeClass>() {

    var someClassType : T

    init(){
    this.someClassType = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<T>
    }

}

-4

यह किसी के लिए उपयोगी हो सकता है। आप java.lang.ref.WeakReference का उपयोग कर सकते हैं; इस तरफ:

class SomeClass<N>{
  WeakReference<N> variableToGetTypeFrom;

  N getType(){
    return variableToGetTypeFrom.get();
  }
}

इस वर्ग का उपयोग कैसे किया जाना चाहिए? क्यों WeakReference? कृपया अपने उत्तर के साथ कुछ स्पष्टीकरण दें, न कि केवल कुछ कोड।
अभिजीत सरकार

इसलिए यदि आपके पास एक है तो आप उस उदाहरण पर SomeClass<MyClass> तुरंत SomeClassकॉल कर सकते getTypeहैं और रनटाइम कर सकते हैं MyClass
२०

ज़रूर, लेकिन क्यों WeakReference? आपने जो कहा है, वह अधिकांश अन्य उत्तरों से अलग नहीं है।
अभिजीत सरकार

पहला मेरा दृष्टिकोण छोटा है (कम कोड), दूसरा कमजोर संदर्भ उनके संदर्भों को अंतिम रूप देने से नहीं रोकता है, और जहां तक ​​मुझे पता है कि यह प्रतिबिंब का उपयोग नहीं करता है, इस प्रकार यह तेज है
TheLetch

यह कुछ भी प्रकार यह है कि प्रकार है, जो, FYI करें, आप आवरण की सचमुच किसी भी प्रकार के साथ कर सकते हैं की एक वस्तु रिटर्न नहीं मिलता है, ( AtomicReference, List, Set)।
5

-5

मैंने इसे एक सरल समझने योग्य और आसानी से समझा जाने वाला समाधान पाया

public class GenericClass<T> {

    private Class classForT(T...t) {
        return t.getClass().getComponentType();
    }

    public static void main(String[] args) {
        GenericClass<String> g = new GenericClass<String>();

        System.out.println(g.classForT());
        System.out.println(String.class);
    }
}

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