2011-11-08 2 views
8

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

//Not legal java code 
public class Foo<C extends Collection<T>> { //where T is another type parameter 
    private C coll; 

    public Foo(C coll) { 
     this.coll = coll; 
    } 

    public void add(T elem){ 
     this.coll.add(elem); 
    } 
    //UPDATED TO ADD GETTER 
    /** 
    * I may need to retrieve the collection again, or pass it 
    * on to another function that needs the specific C type 
    */ 
    public C getColl(){ 
     return coll; 
    } 
} 
... 
List<String> strings = new ArrayList<String>(); 
Foo<List<String>> foo = new Foo<List<String>>(strings); 
foo.add("hello"); 

मुझे पता है कि मैं इसे एक और प्रकार पैरामीटर जोड़कर कर सकता है:

public class Foo<C extends Collection<T>,T> 

लेकिन फिर मैं अनावश्यक जोड़ने के लिए:

Foo<List<String>,String> foo = new Foo<List<String>,String>(strings); 

और मेरी असली दुनिया मामले में, मेरे जेनरिक को कभी-कभी

public class Bar implements Baz<String> 
जैसे लागू क्लॉज में निर्दिष्ट किया जा सकता है

उस दूसरे प्रकार के पैरामीटर को निर्दिष्ट करने के बाद भी और अधिक दर्दनाक है, क्योंकि ऐसा लगता है जैसे यह मेरे चेहरे में कार्यान्वयन विवरण फेंकता है। कहने के लिए

Foo<Bar,String> 

जब वहाँ पहले से ही स्ट्रिंग और बार के बीच एक रिश्ता है बीत रहा है, बस असजीला लगता है। मुझे लगता है कि इसका जावा, जो कि क्षेत्र के साथ जाता है, लेकिन इसके लिए कोई समाधान होने पर बस उत्सुक है।

उत्तर

6

यह संभव नहीं है और मुझे नहीं लगता कि यह आदर्श है क्योंकि आपकी मौजूदा कक्षा में कुछ भी नहीं है जिसके लिए अचूकता की आवश्यकता है।

Foo<T,C extends Collection<T>> 

अधिक आम तौर पर

Foo<T,C extends Collection<? super T>> 

हो सकता है एकमात्र कारण के लिए अगर टी संग्रह का उत्परिवर्तन अनुमति देने के लिए है।

ध्यान दें, अगर आप अक्सर दो प्रकार पैरामीटर निर्दिष्ट करने के लिए होने के बारे में चिंतित हैं, तो आप एक उथले उपवर्ग बना सकते हैं:

class DerivedFoo<T> extends Foo<Collection<T>,T> 

और आप से बचने के लिए कारखाने तरीकों का उपयोग कर सकते हैं निर्माण समय पर डबल-निर्दिष्ट

public static <T> Foo<Collection<T>,T> fromCollection(Collection<T> c) 

तुम भी सार एक interface में इंटरफ़ेस संक्षिप्त प्रकार के लाभ है कि आप ऊपर DerivedFoo को पाने के लिए कर सकते हैं।

+0

फैक्ट्री विधि विचार दिलचस्प है, लेकिन यह अभी भी मुझे परेशान करता है कि टाइप को दो बार निर्दिष्ट किया गया है, भले ही मेरा कोड निर्देशित करता है कि वे हमेशा समान होते हैं। –

+0

@RusselLeggett, ठीक है, तो आपको फिर से invariance की आवश्यकता है, कोई संग्रह ''? हां। यह दर्द है। मेरी सलाह है कि आप अपनी लाइब्रेरी में जटिलता से निपटें और उन कारखानों के जरिए टेर्स एपीआई का पर्दाफाश करने का प्रयास करें जिनके रिटर्न टाइप 'इंटरफेस फू जटिल फू <संग्रहसबटाइप , टी> 'बढ़ाता है ताकि ग्राहक केवल एक पैरामीटर संस्करण का उपयोग कर सकें। –

2

आप क्यों नहीं बस टी अपने ही प्रकार पैरामीटर के रूप में, के रूप में उपयोग नहीं होगा:

Java7 को
public class Foo<T> { //where T is another type parameter 
private Collection<T> coll; 

public Foo(Collection<T> coll) { 
    this.coll = coll; 
} 

public void add(T elem){ 
    this.coll.add(elem); 
} 
+0

मुझे यह देखने में उत्सुकता है कि यह समाधान क्यों नहीं होगा। – ty1824

+3

जैसा कि मैंने कहा, यह एक संक्षिप्त उदाहरण है, लेकिन अगर संग्रह का प्रकार भी परिपक्व हो गया तो क्या होगा। यह एक सूची या एक सेट या एक वृक्षसूची हो सकता है। मान लीजिए कि मैंने फिर से संग्रह को पुनः प्राप्त करने के लिए एक गेटर जोड़ा - प्रकार मायने रखता है। –

2

पहले, कंस्ट्रक्टर्स प्रकार निष्कर्ष नहीं करते हैं, वैकल्पिक हल एक स्थिर कारखाने विधि है। अब यह आवश्यक नहीं है। जावा 7 में आप कर सकते हैं

Foo<List<String>,String> foo = new Foo<>(strings); 

T और C के बारे में, अगर हम उन दोनों के बीच बाधाओं के साथ 2 प्रकार पैरामीटर है, अतिरेक के कुछ डिग्री हो गया। आपके उदाहरण में, चूंकि एक पैरामीटर C पूरी तरह से दूसरे पैरामीटर T को निर्देशित करता है, अनावश्यकता असहनीय लगती है। मुझे कोई समाधान नहीं दिख रहा है।

लेकिन आप शायद बेहतर महसूस कर सकते हैं प्रकार पैरामीटर पुनर्क्रमित रहे हैं

Foo<String,Bar> foo = new Foo<>(bar); 

तो हम घोषित String पहले; फिर Baz<String> प्रदान करें जो Bar