2015-05-18 6 views
15

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

दुर्भाग्य से, मैं पैटर्न का उपयोग करते समय विभिन्न त्रुटियों और चेतावनियों को पूरा करता हूं ताकि मैं कल्पना नहीं कर सकूं, इसका उपयोग कैसे करें।

package tests.java; 

public class Try_GenericInnerRecursion { 

    // base class, consisting of outer and inner parts 
    public static class Outer1<E extends Outer1<E>.Inner1> { 
     public class Inner1 { 
     } 

     public void addElement(E e) { 
      System.out.println("Added " + e.toString()); 
     } 
    } 

    // extending outer, but not inner 
    public static class Outer2<E extends Outer1<E>.Inner1> extends Outer1<E>{ 

    } 

    // extending both outer and inner 
    public static class Outer3<E extends Outer3<E>.Inner3> extends Outer1<E>{ 
     public class Inner3 extends Inner1 { 
     } 
    } 

    // extending both outer and inner and stopping extension 
    public static class Outer4 extends Outer1<Outer4.Inner4> { 
     public class Inner4 extends Outer1<Inner4>.Inner1 { 
     } 
    } 



    // instantiating 
    public static void main(String[] args) { 

     Outer1<Outer1.Inner1> a1; // WARNING: Outer1.Inner1 is a raw type 

     a1 = new Outer1<Outer1.Inner1>(); // WARNING: Outer1.Inner1 is a raw type 

     Outer1<?> a2; // OK 

     a2 = new Outer1<?>(); // ERROR: Cannot instantiate the type Outer1<?> 

     Outer1<Outer1<?>.Inner1> a3; // ERROR: Bound mismatch: The type Outer1<?>.Inner1 is not a valid substitute for the bounded parameter <E extends Outer1<E>.Inner1> of the type Outer1<E> 

    Outer1<? extends Outer1<?>.Inner1> a4; // OK 

    a4 = new Outer1<Outer1.Inner1>(); // ERROR: Type mismatch 

      Outer2<Outer1.Inner1> b1; // WARNING: Outer1.Inner1 is a raw type 

      b1 = new Outer2<Outer1.Inner1>(); // WARNING: Outer1.Inner1 is a raw type 

     // and so on 
    } 

} 

मैं कैसे इस पैटर्न को सही ढंग से उपयोग कर सकते हैं?

+0

तरह का विस्तार 'Outer4' इस तरह के एक प्रकार का उपयोग करने के लिए (क्योंकि अन्यथा प्रकार parameterizing असीम पुनरावर्ती है) एक ही रास्ता है। क्या आपको कोई सख्त घोषणा की आवश्यकता है? 'ई बाहरीबढ़ाता है। इनर 1' सिरदर्द से बहुत कम होगा। आप इन कक्षाओं का उपयोग कैसे करेंगे? – Radiodef

उत्तर

3

मैं आप बस वाइल्डकार्ड कब्जे के दौरान

DerivedCorpus1<?> 

कर सकते हैं विश्वास करते हैं, यह

DerivedCorpus1<x> where x extends Corpus<x>.Element 

जो सही ढंग से घिरा है हो जाता है।

अपने उदाहरण के

DerivedCorpus1<? extends Corpus<?>.Element> 

वाइल्डकार्ड कब्जे के दौरान में, यह

DerivedCorpus1<x> where x extends Corpus<x>.Element 
         and x extends Corpus<?>.Element 

जाहिरा तौर पर हो जाता है, extends Corpus<?>.Element खंड अनावश्यक है।

+0

अभी भी कोई त्रुटि या चेतावनी के साथ कक्षा को तुरंत चालू नहीं कर सकता है। –

3

Outer1<Outer1.Inner1> a1; // WARNING: Outer1.Inner1 is a raw type

वास्तव में, मैं प्राप्त "प्रकार तर्क Outer1.Inner1 प्रकार-चर E` की सीमा के भीतर नहीं है।"

Outer1.Inner1 एक कच्चा प्रकार है, क्योंकि Outer1 एक कच्चा प्रकार है। कच्चे प्रकार का उपयोग करने के लिए, आपको Outer1<something>.Inner1 लिखना होगा। हालांकि, something को बदले में Outer1<something>.Inner1 का विस्तार करना होगा। इस तरह रिकर्सन करने के लिए आपको नामित रिकर्सिव प्रकार की आवश्यकता है। दुर्भाग्यवश, चूंकि Inner1 एक गैर स्थैतिक आंतरिक वर्ग है, इसका Outer1 के उदाहरण के लिए एक अंतर्निहित संदर्भ है, और इसलिए किसी भी वर्ग को विस्तारित करने के लिए Outer1 का एक संलग्न उदाहरण भी होना चाहिए। Outer4 और Inner4 मूल रूप से ऐसा करते हैं।

Outer4 a1 = new Outer4(); // compiles fine 

a2 = new Outer1<?>(); // ERROR: Cannot instantiate the type Outer1<?>

आप new something<?>() ऐसा कभी नहीं कर सकते हैं।

Outer1<Outer1<?>.Inner1> a3; // ERROR: Bound mismatch: The type Outer1<?>.Inner1 is not a valid substitute for the bounded parameter <E extends Outer1<E>.Inner1> of the type Outer1<E>

यह सच है। Outer1<?>.Inner1Outer1<E>.Inner1 का उपप्रकार नहीं है - यह दूसरी तरफ है - Outer1<E>.Inner1Outer1<?>.Inner1 का एक उप प्रकार है। यह सिर्फ ArrayList<?>ArrayList<String> का उप प्रकार नहीं है; यह दूसरा तरीका है।

Outer1<? extends Outer1<?>.Inner1> a4; // OK

क्योंकि आप शीर्ष स्तर पर एक वाइल्डकार्ड है यह ठीक है, और अपने वाइल्डकार्ड के लिए बाध्य प्रकार पैरामीटर E के लिए बाध्य काटती है। वास्तव में, E की मूल सीमा को संतुष्ट करने वाली कोई भी चीज़ इस सीमा को पूरा करनी चाहिए, इसलिए यह बाध्य बेकार है, और यह ऊपर Outer1<?> a2; जैसा ही है।

a4 = new Outer1<Outer1.Inner1>(); // ERROR: Type mismatch

काम करता है नहीं, के लिए, अन्य कारणों के अलावा, एक ही कारण है कि a1 काम नहीं करता है (Outer1.Inner1 संतुष्ट नहीं करता E की बाउंड)। यह अतिरिक्त रूप से आपके बाध्य (Outer1<?>.Inner1) को पूरा नहीं करता है।

Outer2<Outer1.Inner1> b1; // WARNING: Outer1.Inner1 is a raw type

यह वास्तव में एक ही कारण

+0

आपके उत्तर को सारांशित करने का मतलब है कि "जावा में मामले में कक्षा को तुरंत चालू करना असंभव है" सही? –

+0

@SuzanCioc: सही नहीं, क्योंकि उदाहरण के लिए 'Outer4' – newacct

+0

काम करता है लेकिन' Outer4' सामान्य नहीं है। मैं जेनरिकों को तत्काल शुरू करना चाहता हूं। –

1

जेनेरिक विनिर्देश

इससे पहले कि मैं इन्स्टेन्शियशन समस्याओं पर जाने मैं अपने सामान्य संशोधन के लिए, a1 रूप में एक ही त्रुटि देता है परिभाषा:

Outer1<E extends Outer1<E>.Inner1> 

बाहरी 1 मूल रूप से इनर 1 या उसके किसी भी बच्चे वर्ग के तत्वों को रखना चाहिए। इसलिए Outer1 वस्तु के प्रकार प्रासंगिकता का नहीं है और निम्न कोड के साथ बदला जा सकता है:

Outer1<E extends Outer1<?>.Innter1> 

भी विस्तार वर्गों थोड़ा ऊपर उल्लेख किया है का उपयोग करते हुए संशोधित किया गया है।

आरंभ होने

वस्तुओं की इन्स्टेन्शियशन के लिए आप निम्नलिखित ने कहा:

Outer1<Outer1.Inner1> a1;   // WARNING: Outer1.Inner1 is a raw type 
a1 = new Outer1<Outer1.Inner1>(); // WARNING: Outer1.Inner1 is a raw type 

newacct पहले ही उल्लेख किया गया है, Outer1 ही आप नहीं किया था एक सामान्य प्रकार के साथ घोषित किया जाता है ऑब्जेक्ट को तुरंत चालू करते समय निर्दिष्ट करें। कोड इसलिए बाद एक को बदला जाना चाहिए:

Outer1<Outer1<?>.Innter1> a1;   // or simply Outer1<?> a1; 
a1 = new Outer1<Outer1<?>.Innter1>(); // or simply a1 = new Outer1<>(); 

वर्ग है जो कि आधार वर्ग का एक प्रकार के लिए एक आधार वर्ग बढ़ाया असाइन करने के लिए इसी तरह के।

आप जेनेरिक टाइप परिभाषा के साथ निर्दिष्ट करते हैं कि उदाहरण किस प्रकार के तत्व रखेगा।

Outer1<Outer1<?>.Innter1> test; 

की तरह एक घोषणा है कि यह भी सामान्य प्रकार से मेल Outer1 का विस्तार किसी भी इंस्टेंस को स्वीकार करेंगे।इसका मतलब है आप केवल असाइन कर सकते हैं

test = new Outer1<Outer1<?>.Inner1>(); 
test = new Outer2<Outer2<?>.Inner1>(); 
इसे करने के लिए

, लेकिन नहीं Outer3 या यहाँ तक कि Outer4!

भले ही आप कोड को आगे बढ़ाने के लिए कोड को संशोधित करते हैं।

public static class Outer5<E extends Outer1<?>.Inner1> extends Outer1<E>{ 
    public class Inner5 extends Inner1 { 
    } 
} 

तुम सिर्फ

test = new Outer5<Outer5<?>.Inner1>(); 

नहीं बल्कि

test = new Outer5<Outer5<?>.Inner5>(); // FAILS! 

कुछ है कि प्रकार तर्क के रूप में परिभाषित किया गया Inner1 में जोड़ने के लिए सक्षम हैं।

हालांकि, वास्तव में इस मुद्दे का एक बहुत ही सरल समाधान है। आप इस तरह से वस्तु को परिभाषित हैं:

Outer1<? extends Outer1<?>.Inner1> test2; 

आप वास्तव में निम्नलिखित बातें कर पा रहे हैं:

test2 = new Outer1<Outer1<?>.Inner1>(); 
test2 = new Outer2<Outer2<?>.Inner1>(); 
test2 = new Outer3<Outer3<?>.Inner3>(); 
test2 = new Outer4(); 
test2 = new Outer5<Outer1<?>.Inner1>(); 
test2 = new Outer5<Outer5<?>.Inner1>(); 
test2 = new Outer5<Outer5<?>.Inner5>(); 

के रूप में आप अब स्पष्ट रूप से संकलक से कहा कि या तो Inner1 प्रकार या उसके किसी भी एक्सटेंशन की अनुमति है।

कोड

मैं अपने कोड अद्यतन और सत्यापित करने के लिए है कि वास्तव में किए गए परिवर्तनों को किसी भी कारण स्पष्ट प्रकार तर्क निर्दिष्ट करने के लिए redundant type arguments in new expression के अलावा त्रुटि या चेतावनी संकलन का उत्पादन नहीं करते नए असाइनमेंट के एक जोड़े को जोड़ दिया है हीरा ऑपरेटर <> उपयोग करने के बजाय:

public class GenericInnerRecursion 
{ 
    // base class, consisting of outer and inner parts 
    public static class Outer1<E extends Outer1<?>.Inner1> { 
     public class Inner1 { 
     } 

     public void addElement(E e) { 
      System.out.println("Added " + e.toString()); 
     } 
    } 

    // extending outer, but not inner 
    public static class Outer2<E extends Outer1<?>.Inner1> extends Outer1<E>{ 

    } 

    // extending both outer and inner 
    public static class Outer3<E extends Outer3<?>.Inner3> extends Outer1<E>{ 
     public class Inner3 extends Inner1 { 
     } 
    } 

    // extending both outer and inner and stopping extension 
    public static class Outer4 extends Outer1<Outer4.Inner4> { 
     public class Inner4 extends Outer1<Inner4>.Inner1 { 
     } 
    } 

    public static class Outer5<E extends Outer1<?>.Inner1> extends Outer1<E>{ 
     public class Inner5 extends Inner1 { 
     } 
    } 


    // instantiating 
    public static void main(String[] args) { 

     Outer1<Outer1<?>.Inner1> a1; 
     a1 = new Outer1<Outer1<?>.Inner1>(); 

     Outer1<?> a2; 
     a2 = new Outer1<>(); 

     Outer1<Outer1<?>.Inner1> a3; 

     Outer1<? extends Outer1<?>.Inner1> a4; 
     a4 = new Outer1<Outer1<?>.Inner1>(); 

     Outer2<Outer1<?>.Inner1> b1; 
     b1 = new Outer2<Outer1<?>.Inner1>(); 

     // and so on 

     // assigning extension-classes to the parent-class 
     Outer1<Outer1<?>.Inner1> c1; 
     c1 = new Outer2<Outer2<?>.Inner1>(); 
     // assigning inner-extension-classes to parent-class 
     Outer1<Outer3<?>.Inner3> c2; 
     c2 = new Outer3<Outer3<?>.Inner3>(); 
     // assigning extension class without specified generics to parent class 
     Outer1<Outer4.Inner4> c3; 
     c3 = new Outer4(); 

     Outer1<Outer1<?>.Inner1> test; 
     test = new Outer1<>(); 
     test = new Outer2<>(); 
     test = new Outer5<Outer5<?>.Inner1>(); 

     Outer1<? extends Outer1<?>.Inner1> test2; 
     test2 = new Outer1<Outer1<?>.Inner1>(); 
     test2 = new Outer2<Outer2<?>.Inner1>(); 
     test2 = new Outer3<Outer3<?>.Inner3>(); 
     // new Outer3<Outer3<?>.Inner1>(); not possible as generic type extends Outer3<?>.Inner3 and not Outer1<?>.Inner1! 
     test2 = new Outer4(); 
     test2 = new Outer5<Outer1<?>.Inner1>(); 
     test2 = new Outer5<Outer5<?>.Inner1>(); 
     test2 = new Outer5<Outer5<?>.Inner5>(); 
    } 
} 
संबंधित मुद्दे

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