2012-09-22 9 views
12

मैं एक वर्ग एक ही प्रकार के दो मानों की एक जोड़ी का प्रतिनिधित्व करने के लिए है (प्रकार है जो हो सकता है प्रकार की एक विशिष्ट सेट के किसी भी):जावा जेनरिक सीमाएं या गलत उपयोग?

public class Pair<E extends AClass>{ 
     private E var1; 
     private E var2; 
    } 

इस वर्ग एक रूपरेखा द्वारा प्रयोग किया जाता है, इसलिए यह एक नहीं की जरूरत है -argument निर्माता है, जिसमें मेरे पास 2 चर (var1, var2) का दृष्टांत के लिए:

public class Pair<E extends AClass>{ 
     private E var1; 
     private E var2; 

     public Pair(){ 
      var1 = invoke constructor of type E; 
      var2 = invoke constructor of type E 
     } 
    } 

वहाँ स्पष्ट रूप से यहाँ कई समस्याओं का कर रहे हैं:

  1. में वेरिएबल्स को तुरंत चालू करने के लिए मुझे किसी भी तरह का सटीक प्रकार पता होना चाहिए और उस विशिष्ट प्रकार के कन्स्ट्रक्टर का आह्वान करना चाहिए; सबसे अच्छा मामले में यह, की तरह कुछ निर्माता में एक बहुत बड़ी है, तो किसी और बयान का मतलब:

    public Pair(){ 
         if(var1 instanceof SpecificType1){ 
          var1 = new SpecificType1(); 
          var2 = new SpecificType2(); 
         } 
        } 
    
  2. यहां तक ​​कि अगर मैं के रूप में ऊपर करते हैं, मैं कुछ समस्याओं का होगा क्योंकि var1 प्रकार ई और मैं की घोषणा की जाती है SpecficType1 को तुरंत चालू करने और परिणामस्वरूप ऑब्जेक्ट var1/var2 को असाइन करने के लिए प्रयास करते समय एक प्रकार की मिलान त्रुटि प्राप्त होगी। आदेश यह काम करने के लिए, मैं ई को कास्ट करने के लिए है:

    var1 = (E)new SpecificType1(); 
    

लेकिन इस संकलन समय प्रकार के रूप में मैं एक सामान्य प्रकार के लिए एक विशेष प्रकार कास्ट करने के लिए कोशिश कर रहा हूँ जाँच नष्ट कर देता है।

क्या यह जावा में जेनेरिक की एक सीमा है या क्या यह परिदृश्य जेनेरिक का उपयोग करने के लिए एक बुरा है?

+1

यदि आपको एक सामान्य कंटेनर के अंदर 'instanceOf' का उपयोग करना है, तो आपके पास एक डिज़ाइन समस्या है। –

+0

आप [class.forName()] (http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Class.html#forName%28java.lang.String%29) आज़मा सकते हैं –

+0

पूछने वाले को अधिसूचना (चूंकि संपादन पूछताछ को सूचित नहीं करते हैं): मैंने एक साधारण कोड नमूना जोड़ा है कि आपके मामले में फैक्टरी डिजाइन पैटर्न का उपयोग कैसे करें – amit

उत्तर

6

चर को तुरंत चालू करने के लिए मुझे किसी भी तरह का सटीक प्रकार पता होना चाहिए और उस विशिष्ट प्रकार के कन्स्ट्रक्टर का आह्वान करना चाहिए; सबसे अच्छे मामले में इसका मतलब है कि कन्स्ट्रक्टर में अन्य कथन, अगर कुछ:

इससे पहले आप समस्याओं में भाग लेंगे।

if(var1 instanceof SpecificType1){ 
     var1 = new SpecificType1(); 
     var2 = new SpecificType2(); 
    } 

var1 इस बिंदु पर null है, इसलिए var1 instanceof T सभी T के लिए false है। जावा जेनरिक की


एक सीमा है कि जेनेरिक प्रकार पैरामीटर erased तो वहाँ कोई रास्ता नहीं है कि आप एक शून्य तर्क निर्माता से प्रकार पैरामीटर पर प्रतिबिंबित कर सकते हैं कर रहे हैं।

कॉलर को आपको कुछ संदर्भ प्रदान करना है कि आपको var1 और var2 प्रारंभ करना है, और यह संदर्भ प्रदान करने का सामान्य तरीका कन्स्ट्रक्टर तर्कों के माध्यम से है।


आपका सबसे अच्छा विकल्प शायद var1 जाने के लिए और null शुरू और फिर जाने तक प्रारंभ में देरी var2 के रूप में आप संदर्भ आप की जरूरत मिल सकता है।

शायद

void init(Class<E> type) { 
    if (type.isAssignableFrom(ConcreteType1.class)) { 
    var1 = type.cast(new ConcreteType1(...)); 
    var2 = type.cast(new ConcreteType1(...)); 
    } else { /* other branches */ } 
} 

इस के बाद से आप अभी भी E extends List<Number> से E extends List<String> भेद कर सकते हैं नहीं है, लेकिन यह आपके मामले के लिए काफी अच्छा हो सकता है, और .cast विधि आप के लिए एक प्रकार सुरक्षित डाली दे देंगे सही नहीं है E


वैकल्पिक रूप से, अमरूद, Guice, और संबंधित पुस्तकालयों Supplier<E> इंटरफ़ेस जो एक init विधि में काम में आ सकता है जैसी चीजों प्रदान करते हैं।

+0

हां, यह भी मेरा अंतर्ज्ञान था। तो, सीमाएं और भी गंभीर हैं! – Razvan

+0

मैं भी संपादन से सहमत हूं। मेरे पास एक और कन्स्ट्रक्टर है जो पैरामीटर के रूप में 2 ई चर लेता है, लेकिन ढांचा एक नो-एर्ग कन्स्ट्रक्टर – Razvan

+0

चाहता है ढांचे को इनिट कॉल करना होगा और यह निश्चित रूप से ऐसा नहीं करेगा। – Razvan

2

आप एक सामान्य प्रकार को तत्काल नहीं कर सकते - उदाहरण के लिए यदि सामान्य प्रकार SomeAbstractClass है तो क्या होगा? तत्काल क्या होगा? (यह नहीं हो, यह सिर्फ अंतर्ज्ञान है है)

हालांकि, अगर आप java reflection API का उपयोग वस्तु का दृष्टांत कर सकते हैं - लेकिन आप इसके लिए विशिष्ट वर्ग वस्तु की आवश्यकता होगी।

एक और अधिक सुरुचिपूर्ण विकल्प abstract factory design pattern उपयोग कर रहा है, और अपने जोड़ी के लिए एक कारखाने वस्तु गुजरती हैं, और इसका इस्तेमाल की जरूरत वस्तु के निर्माण के लिए।


कोड का नमूना:

public class Pair<S> { 
    public final S var1; 
    public final S var2; 
    public Pair(Factory<S> builder) { 
     var1 = builder.build(); 
     var2 = builder.build(); 

    } 
} 

public interface Factory<S> { 
    public S build(); 
} 

public class IntegerBuilder implements Factory<Integer> { 
    private int element = 5; 
    public Integer build() { 
     return new Integer(element++); 
    } 
} 
+0

कुछ नमूना कोड हमेशा स्वागत है। – OldCurmudgeon

+0

@ ओल्डकुरमुडियन: बस किया, क्या यह समझ में आता है? – amit

+0

उत्कृष्ट। और अब 'कक्षा' विधि के लिए, केवल पूर्णता के लिए। – OldCurmudgeon

1

एक रूपरेखा यह दृष्टांत के लिए गए थे, तो यह है कि यह एक कच्चे प्रकार के रूप में करना होगा, कोई प्रकार पैरामीटर के साथ कुछ new Pair() के बराबर है।

class SpecificType1Pair extends Pair<SpecificType1> {} 

और उन्हें ढांचे के बजाय पारित:

मैं आप की तरह सरल एक लाइनर कक्षाएं बनाने के लिए लगता है। आप वास्तविक प्रकार पैरामीटर getClass().getGenericSuperclass()).getActualTypeArguments()[0] के रूप में प्राप्त कर सकते हैं। आप कक्षा जोड़ी इस तरह दिखेगी:

public abstract class Pair<E extends AClass> { 
    private E var1; 
    private E var2; 

    public Pair() { 
     ParameterizedType superclass = (ParameterizedType) getClass().getGenericSuperclass(); 
     @SuppressWarnings("unchecked") 
     Class<E> clazz = (Class<E>) superclass.getActualTypeArguments()[0]; 
     try { 
      var1 = clazz.newInstance(); 
      var2 = clazz.newInstance(); 
     } catch (InstantiationException e) { 
      handle(e); 
     } catch (IllegalAccessException e) { 
      handle(e); 
     } 
    } 
} 
+1

'@SuppressWarnings (" अनचेक ")' कक्षा क्लैज = (कक्षा ) ...; 'लाइन पर हो सकता है। –

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