2009-06-16 37 views
49

निर्धारित मैं इस तरह के रूप में, एक जावा वर्ग सामान्य हो बनाने रहा हैं:जावा जेनेरिक वर्ग - प्रकार

public class Foo<T> 

कैसे एक आंतरिक रूप से उस वर्ग, क्या 'टी' किया जा रहा समाप्त हो गया करने के लिए निर्धारित कर सकते हैं?

public ???? Bar() 
{ 
    //if its type 1 
    // do this 
    //if its type 2 
    // do this 
    //if its type 3 
    // do this 
    //if its type 4 
    // do this 
} 

मैं जावा एपीआई के आसपास poked और प्रतिबिंब सामान के साथ खेला है, instanceof, getClass, .class, आदि, लेकिन मैं सिर या उनमें से पूंछ बनाने के लिए नहीं कर पा रहे। मुझे लगता है कि मैं करीब हूं और बस कई कॉलों को गठबंधन करने की आवश्यकता है, लेकिन कम आना जारी रखें।

अधिक विशिष्ट होने के लिए, मैं यह निर्धारित करने का प्रयास कर रहा हूं कि कक्षा को 3 संभावित प्रकारों में से एक के साथ तत्काल किया गया था या नहीं।

+15

इस लगभग एक बुरा डिजाइन पसंद होने की गारंटी है करने की इच्छा। संभावना है कि अगर बयान लागू किया जा करने के लिए प्रत्येक "प्रकार" के ज्ञान की आवश्यकता है, इसलिए आप शायद उन सभी वर्गों एक ही मूल प्रकार का होना चाहिए, और "ऐसा करते हैं" एक आभासी विधि होना चाहिए। इसमें कक्षाओं को लपेटना शामिल हो सकता है, लेकिन यदि आप इस सड़क पर जाते हैं तो कुल मिलाकर आपका डिज़ाइन बेहतर होगा। –

+2

यदि बयानों में संभावनाएं सभी संभव कॉलिंग प्रकारों के बीच बढ़त के मामले हैं, जिन्हें पूरी तरह से अलग कार्यान्वयन की आवश्यकता होती है। मैं यहां जो कह रहा हूं उसके साथ समझौता कर रहा हूं, लेकिन विशिष्ट आवेदन एक चट्टान और एक कठिन जगह है। –

+1

सामान्य प्रकार के परम के लिए कक्षा प्राप्त करने की आवश्यकता हमेशा खराब डिजाइन निर्णय नहीं होती है। एक वैध आवश्यकता (मेरा! :) एक विधि कॉल हो सकता है जिसके लिए कक्षा <> पैरामीटर की आवश्यकता होती है। – dahvyd

उत्तर

58

मैं क्या वह यहाँ कुछ परियोजनाओं के लिए बताते हैं करने के लिए इसी तरह की एक समाधान का इस्तेमाल किया और यह बहुत उपयोगी पाया है।

http://blog.xebia.com/2009/02/07/acessing-generic-types-at-runtime-in-java/

यह की jist उपयोग कर रहा है निम्नलिखित:

public Class returnedClass() { 
    ParameterizedType parameterizedType = (ParameterizedType)getClass() 
               .getGenericSuperclass(); 
    return (Class) parameterizedType.getActualTypeArguments()[0]; 
} 
+0

+1! मैं इस –

+0

+1 के बारे में लिखने जा रहा था और यह आगे के शोध के बाद मैंने जो समाधान किया था, उतना ही है, इसलिए मैंने इसे अपने स्वीकृत उत्तर में बदल दिया है। –

+0

+1 उत्कृष्ट! मैं इसे घंटों के लिए खोज रहा था ... –

12

type erasure की वजह से, इसे सीधे करने का कोई तरीका नहीं है। आप क्या कर सकते हैं, हालांकि, Class<T> को कन्स्ट्रक्टर में पास कर दें और अपनी कक्षा के अंदर इसे पकड़ें। फिर आप इसे तीन संभावित Class प्रकारों के विरुद्ध देख सकते हैं जिन्हें आप अनुमति देते हैं।

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

+0

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

+0

फिर से, मैं आपको आग्रह करता हूं कि आप प्रकार के आधार पर एक if-statement के बजाय बहुरूपता पर दृढ़ता से विचार करें। –

+0

दुर्भाग्य से विचाराधीन वस्तुओं किसी भी तरह से संबंधित नहीं हैं, इसलिए एक बहुलक समाधान व्यावहारिक नहीं है। यदि संभव हो तो कथन-तर्क तर्क में आने वाली संभावित वस्तुएं अन्य सभी 'सामान्य' प्रसंस्करण के किनारे के मामले हैं, जिनका कोई संबंध नहीं है, पूरी तरह अलग तरीके से पूरी तरह से इलाज किया जाना चाहिए। –

0

एक सामान्य वर्ग के पूरे मुद्दे है कि आप न प्रकार है कि इस्तेमाल किया जा रहा पता करने की जरूरत है ....

+2

सच है, हालांकि अगर मैं किसी वर्ग को डिज़ाइन करता हूं जिसे सामान्य रूप से किसी भी प्रकार के होने के लिए तुरंत चालू किया जा सकता है, तो मैं विशिष्ट तर्क के साथ किनारे के मामलों के रूप में सभी संभावित प्रकारों के एक विशिष्ट सबसेट को संभालना चाहता हूं। –

+0

फिर विभिन्न उपप्रकार बनाएं। या रणनीतियों (या इसी तरह) के लिए प्रतिनिधि। –

3

समस्या है कि जेनेरिक सामान का सबसे संकलन के दौरान गायब हो जाएगा है।

ऑब्जेक्ट के निर्माण के दौरान प्रकार को सहेजना एक आम समाधान है।

जावा का प्रकार मिटाना व्यवहार में एक संक्षिप्त परिचय के लिए पढ़ने के लिए इस page

+1

यह बहुत उपयोगी है - मैंने ऐसे समाधान देखे हैं जिनमें यह शामिल है और इस मार्ग पर जा सकते हैं। –

+1

शायद इसका मतलब है कि आपका डिज़ाइन खराब है। सी # के साथ व्यापक जानकारी और इसके विपरीत के लिए –

0

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

44

.NET जावा जेनरिक के विपरीत "टाइप एरर" नामक तकनीक द्वारा कार्यान्वित किया जाता है।

इसका मतलब यह है कि संकलक वर्ग फ़ाइलों को उत्पन्न करते समय प्रकार की जानकारी का उपयोग करेगा, लेकिन इस जानकारी को बाइट कोड में स्थानांतरित नहीं करेगा। यदि आप जवाप या इसी तरह के टूल के साथ संकलित कक्षाओं को देखते हैं, तो आप पाएंगे कि List<String> क्लास फ़ाइल में एक साधारण List (Object) है, जैसा कि यह पूर्व-जावा -5 कोड में था।

जेनेरिक सूची तक पहुंचने वाले कोड को संकलक द्वारा "पुनर्लेखित" किया जाएगा जिसमें आपको पहले के संस्करणों में खुद को लिखना होगा।

जावा 5:

List<String> stringList = new ArrayList<String>(); 
stringList.add("Hello World"); 
String hw = stringList.get(0); 

जावा 1.4 और इससे पहले कि: वास्तव में निम्नलिखित दो कोड के टुकड़े एक बाइट कोड के नजरिए से समान एक बार संकलक उन लोगों के साथ किया जाता है कर रहे हैं

List stringList = new ArrayList(); 
stringList.add("Hello World"); 
String hw = (String)stringList.get(0); 

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

पूरी बात मौजूदा libs पुन: संयोजित करने के लिए किसी भी आवश्यकता के बिना अंतर-संचालित पुराने पुस्तकालयों और नई generified कोड रखने के लिए किया गया था। यह .NET मार्ग पर एक बड़ा फायदा है जहां सामान्य वर्ग और गैर-जेनेरिक लोग एक साथ रहते हैं लेकिन स्वतंत्र रूप से इनकार नहीं किए जा सकते हैं।

दोनों दृष्टिकोण उनके पक्ष-विपक्ष है, लेकिन है कि जिस तरह से यह जावा में है।

अपने मूल प्रश्न के लिए वापस पाने के लिए: आप, कार्यावधि में प्रकार की जानकारी पर प्राप्त करने के लिए सक्षम नहीं होगा क्योंकि यह बस नहीं वहाँ अब और, एक बार संकलक अपने काम किया है है। यह निश्चित रूप से कुछ तरीकों से सीमित है और इसके आसपास कुछ क्रैकी तरीके हैं जो आम तौर पर कक्षा-उदाहरण को संग्रहीत करने पर आधारित होते हैं, लेकिन यह एक मानक विशेषता नहीं है।

+2

+1 - धन्यवाद –

+1

धन्यवाद। मुझे खेद है कि कोई +10 बटन नहीं है। –

0

मैं व्यक्तित्व के साथ सहमत हैं। जेनेरिक संकलन-समय सत्यापन के लिए है, रनटाइम गतिशील टाइपिंग नहीं। आपको जो चाहिए वह लगता है वास्तव में सिर्फ कारखाना पैटर्न है। लेकिन अगर आपका "ऐसा करें" तत्काल नहीं है, तो एक साधारण एनम शायद भी काम करेगा। माइकल ने क्या कहा, अगर आपके पास थोड़ा और ठोस उदाहरण है, तो आपको बेहतर उत्तर मिलेंगे।

+0

मुझे यहां असहमत होना है, और विशिष्ट समस्या स्थान में आवश्यक गैर-पॉलीमोर्फिक समाधान के कई उल्लेख हुए हैं, और मुझे प्राप्त उत्तरों के साथ मैं काफी खुश हूं। –

1

आप कुछ विशिष्ट प्रकार है कि सार्थक कर रहे हैं पता है, तो आप कार्यान्वयन के साथ अपने सामान्य प्रकार के उपवर्गों बनाना चाहिए।

तो

public class Foo<T> 

public ???? Bar() 
{ 
    //else condition goes here 
} 

और फिर

public class DateFoo extends Foo<Date> 

public ???? Bar() 
{ 
    //Whatever you would have put in if(T == Date) would go here. 
} 
संबंधित मुद्दे