2012-06-22 14 views
8

कल्पना कीजिए इस परिदृश्य:जावा में सामान्य पैरामीटर की कक्षा के लिए प्रतिबिंब?

class MyClass extends OtherClass<String>{ 

    String myName; 
    //Whatever 

} 

class OtherClass<T> { 

    T myfield; 

} 

और मैं विशेष रूप से प्रतिबिंब का उपयोग (MyClass.class).getDeclaredFields() MyClass का विश्लेषण कर रहा हूँ, इस मामले में मैं निम्नलिखित (() फील्ड की और प्रकार, GetType का प्रयोग करके) क्षेत्रों मिल जाएगा:

myName --> String 
myField --> T 

मैं टी के लिए वास्तविक प्रकार है, जो स्पष्ट "स्ट्रिंग" की वजह से कार्यावधि में जाना जाता है पाने के लिए अंकन फैली में चाहते हैं, मैं myField के गैर आनुवंशिक प्रकार हो रही है के बारे में कैसे जाते हैं?

संपादित समाधान किया गया:

लगता है की तरह जवाब "आप नहीं कर सकते" है। जो लोग इस सवाल पर विचार कर सकता के लिए बाद में मैं जैक्सन का उपयोग कर (मैं यह करने के लिए JSON उत्पन्न करने के लिए कोशिश कर रहा था) और इस तरह से अपने वर्गों और क्षेत्रों व्याख्या ताकि जैक्सन वंशानुगत पदानुक्रम के बारे में पता है की सलाह देते हैं और स्वचालित रूप से क्या कर सकते हैं नीचे दिए गए सही उत्तर का सुझाव दिया।

+1

उत्तर यह नहीं है कि आप नहीं कर सकते; आप आसानी से टाइप पैरामीटर से स्पष्ट प्रकार के तर्कों के लिए एक नक्शा बना सकते हैं। टाइप एरर – Jeffrey

उत्तर

18

इस प्रकार का विलोपन की वजह से, प्रतिबिंब सिर्फ इसलिए आप स्पष्ट रूप से String इस्तेमाल किया हासिल किया जा सकता अन्यथा इस जानकारी होगा खो दिया गया है।

ParameterizedType t = (ParameterizedType) MyClass.class.getGenericSuperclass(); // OtherClass<String> 
Class<?> clazz = (Class<?>) t.getActualTypeArguments()[0]; // Class<String> 
+0

ऐसा लगता है कि आप पूरी प्रतिक्रिया के लिए प्रतियोगिता जीतते हैं :) – Jochen

+0

यह एक अच्छा जवाब है, हालांकि मैं सामान्य रूप से फील्ड ऑब्जेक्ट के साथ ऐसा कैसे कर सकता हूं? मैं स्पष्ट रूप से सुपर क्लास के लिए नहीं पूछना चाहता क्योंकि मैं बस अपने उप-वर्ग के सभी घोषित क्षेत्रों को प्राप्त करने की कोशिश कर रहा हूं, जिनमें से एक सामान्य है। मुझे बस कुछ मिलता है जैसे किक्लेक्डफिल्ड्स(), लेकिन जेनेरिक के बारे में बेहतर। क्या इसका कोई मतलब है? –

+0

@hatboysam एक तरीका या दूसरा आपको सुपर क्लास के लिए पूछना है। 'Field.getGenericParameter 'को कॉल करने से केवल प्रकार पैरामीटर (इस मामले में' टी') वापस आ जाएगा, स्पष्ट प्रकार तर्क (' स्ट्रिंग') नहीं। आप इस प्रकार पैरामीटर को ले सकते हैं और 'MyClass.class.getSuperclass() से नक्शा बनाकर स्पष्ट प्रकार तर्क प्राप्त कर सकते हैं। GetTypeArguments() '' 'MyClass.class.getGenericSuperclass()। GetActualTypeArguments()'। कास्टिंग के साथ – Jeffrey

-4

Type Erasure की वजह से वास्तविक प्रकार प्राप्त करने के लिए कोई सीधा तरीका नहीं है। हालांकि आप निम्नलिखित तरीके से उपयोग कर सकते हैं: अपने OtherClass<T> में

, निम्नलिखित सार विधि लिखें:

@Override 
protected Class<String> getClazz(){ 
    return String.class; 
} 

तो आप getClazz() कॉल कर सकते हैं:

protected abstract class<T> getClazz(); 

फिर MyClass में, आप विधि को लागू कक्षा पाने के लिए।

+0

+1 ओपी ने अपने जेनेरिक क्लास के लिए एक ठोस प्रकार पैरामीटर दिया, वह जानकारी * रनटाइम पर रखी गई है और इसे पुनर्प्राप्त किया जा सकता है। – BlackVegetable

+2

के लिंक के लिए – Jeffrey

+0

-1 - यह समाधान इस पोस्ट पर ध्यान दिए गए अन्य लोगों की तरह अनावश्यक है।साथ ही, आपके 'getClass()' के पास अंतिम विधि ['ऑब्जेक्ट # getClass()'] (http://docs.oracle.com/javase/7/docs/api/java/lang/Object] के साथ एक नाम संघर्ष होगा .html # getClass \ (\)) –

0

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

अपने विशेष मामले में, MyClass.class.getGenericSuperclass() पर कॉल करने से आपको वह जानकारी मिल सकती है, क्योंकि कुछ अजीब कारणों से, जब विरासत को कक्षा वर्णक में रखा जाता है तो ठोस प्रकार का उपयोग किया जाता है।

+2

में नहीं प्राप्त कर सकते हैं यह "कुछ अजीब कारण" नहीं है। * फ़ील्ड, विधियों, सुपरक्लास, कक्षाओं को संलग्न करने आदि की घोषणाएं हमेशा रखी जाती हैं, क्योंकि अन्य वर्गों को संकलन करते समय उनका उपयोग करने की आवश्यकता होती है। यह रनटाइम प्रकार की वस्तुओं से एक अलग मुद्दा है, जहां कोई जेनरिक नहीं है। – newacct

3

मैं एक अच्छा विवरण here पाया:

क्रम एक parameterizable प्रकार ही निरीक्षण, java.util.List की तरह, जानते हुए भी है कि किस प्रकार के parameterized किया गया है का कोई रास्ता नहीं है जब। यह समझ में आता है क्योंकि उसी प्रकार के प्रकार को सभी प्रकार के प्रकारों में पैरामीटर किया जा सकता है। लेकिन, जब तुम विधि या क्षेत्र है कि एक पैरामिट्रीकृत प्रकार का उपयोग वाणी का निरीक्षण किया, तो आप क्रम किस प्रकार paramerizable प्रकार के parameterized किया गया था पर देख सकते हैं।

संक्षेप में:

आप एक प्रकार ही किस प्रकार यह एक क्रम को पैरामिट्रीकृत है पर नहीं देख सकते हैं, लेकिन आप के खेतों और तरीकों में देख सकते हैं, जहां उसका उपयोग और पैरामिट्रीकृत है।

कोड में:

आप T यहाँ नहीं देख सकते हैं:

class MyClass<T> { T myField; } 

आप "T" यहाँ देख सकते हैं:

class FooClass { 
    MyClass<? extends Serializable> fooField; 
} 

यहाँ आपको बता करने में सक्षम होगा fooField के पैरामीटर टाइप करें और टाइप करें। getGeneric*()Class और Method के तरीके देखें।

वैसे, मैं अक्सर देखते हैं कि यह (छोटा):

Class fieldArgClass = (Class) aType.getActualTypeArguments()[0]; 

यह सही नहीं है क्योंकि getActualTypeArguments() हो सकता है, और अक्सर, TypeVariable वापस आ जाएगी वर्ग के बजाय - कि जब सामान्य <? extends SomeClass> बजाय है बस <SomeClass>। यह गहरी जा सकते हैं, कल्पना:

class FooClass { 
    MyClass<? extends Map<String, List<? extends Serializable>>> fooField; 
} 

तो तुम Type एस के एक पेड़ मिलता है। लेकिन यह थोड़ा सा विषय है। आनंद लें :)

0

यह एक उत्कृष्ट उदाहरण है कि क्यों प्रतिबिंब एक अच्छा विचार नहीं है।

प्रतिबिंब द्वारा किसी प्रोग्राम से आप क्या प्राप्त कर सकते हैं केवल वे तथ्यों हैं जो भाषा के लिए संकलक लोगों को उपलब्ध कराने के लिए चुना गया है।

और वे आम तौर पर सब कुछ उपलब्ध कराने के लिए बर्दाश्त नहीं कर सकते हैं; वे कच्चे कार्यक्रम के पाठ को चारों ओर रखना चाहते हैं।

इस प्रकार आपके कोड के बारे में अन्य सभी तथ्य प्रतिबिंबित करने के लिए उपलब्ध नहीं हैं।

इस के लिए इलाज बाहर कदम भाषा और एक उपकरण है जो कोड के बारे में जानकारी के किसी भी मनमाने ढंग से बिट प्रदान कर सकते हैं उपयोग करने के लिए है। ऐसे टूल्स को Program Transformation Systems (PTS) कहा जाता है।

एक पीटीएस स्रोत कोड का विश्लेषण करता है और इसका प्रतिनिधित्व करता है एएसटी बनाता है। एक अच्छा पीटीडब्ल्यू एक एएसटी का निर्माण करेगा जो अनिवार्य रूप से कोड (ऑपरेटरों, ऑपरेटरों, विराम चिह्न, टिप्पणियों) के बारे में सबकुछ रखता है ताकि इसका निरीक्षण किया जा सके। आम तौर पर एक पीटीएस भाषा टोकन की लाइन/कॉलम स्थिति रिकॉर्ड करेगा, यहां तक ​​कि लेआउट जानकारी भी उपलब्ध है; चरम पीटीएस टोकन के बीच अंतराल में सफेद जगह रिकॉर्ड करेगा या कम से कम पता होगा कि इसके बारे में पूछे जाने पर मूल पाठ फ़ाइल को कैसे पढ़ा जाए। यह एएसटी संक्षेप में पूर्ण पाठ के बराबर है जो मैंने कहा होगा, लेकिन प्रक्रिया के लिए एक और सुविधाजनक रूप में।

(PTSs एक अन्य बहुत अच्छा संपत्ति हैं: वे एएसटी को संशोधित करने और संशोधित कार्यक्रम के लिए कोड पुनः लेकिन उस से ऊपर है और प्रतिबिंब परे तो मैं इस पहलू पर आगे टिप्पणी नहीं करेंगे।)।

संबंधित मुद्दे