2009-05-02 9 views
8

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

नीचे दिए गए नमूना पर, संकलक मुझे एक त्रुटि दे रहा है

प्रेषण (नई AlphabetSoup());

विधि प्रेषण (Demo.Soup) प्रकार डेमो

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

प्रेषण ((सूप) नई AlphabetSoup())

लेकिन मैं अनिश्चित कैसे आप एक कॉल दिखाना चाहते हूँ दूसरे संस्करण के लिए। क्या यह संभव है?

public class Demo { 

    interface HasA { public char getA(); } 
    interface HasB { public char getB(); } 
    interface HasC { public char getC(); } 

    interface Soup { 
     public void eat(); 
    } 

    class Alphabet implements HasA, HasB, HasC { 
     public char getA() { return 'a'; } 
     public char getB() { return 'b'; } 
     public char getC() { return 'c'; } 
    } 

    class AlphabetSoup implements Soup, HasA, HasB, HasC { 
     public void eat() { System.out.println("Mmm Mmm Good!"); } 
     public char getA() { return 'a'; } 
     public char getB() { return 'b'; } 
     public char getC() { return 'c'; } 
    } 

    public void dispatch(Soup soup) { 
     System.out.println("Eating some soup..."); 
     soup.eat(); 
    } 

    public <T extends HasA & HasB & HasC> void dispatch(T letters) { 
     System.out.println("Reciting ABCs..."); 
     System.out.println(letters.getA()); 
     System.out.println(letters.getB()); 
     System.out.println(letters.getC()); 
    } 

    public void test() { 
     dispatch(new Alphabet()); 
     dispatch(new AlphabetSoup()); 
    } 


    public static void main(String[] args) { 
     new Demo().test(); 
    } 
} 

- संपादित करें: बस सीखा है कि चौराहे प्रकार "

+0

मेरा मानना ​​है कि अन्य प्रेषण विधि को कॉल करने का एकमात्र संभावित तरीका प्रतिबिंब का उपयोग कर है। –

उत्तर

1

ध्यान दें कि आप एक वास्तविक समस्या नहीं है, तरीके के रूप में आप में रुचि रखते हैं" कई घिरे प्रकार पैरामीटर औपचारिक रूप से रूप में भेजा जाता " बुला पहले से ही वजह से गतिशील बाइंडिंग के लिए कहा जाता है

dispatch((Soup) new AlphabetSoup()); पैदावार चल रहा है:। इसलिए,

Reciting ABCs... 
a 
b 
c 
Eating some soup... 
Mmm Mmm Good! 

मूल polymorphic व्यवहार के कारण AlphabetSoup विधि पहले से ही बुलाया जाता है।

6

कंपाइलर सही है, और आपको एक गड़बड़ी से बचाता है।

AlphaBetSoup सूप का एक उप-प्रकार और भी हासा, HasB, और HasC की एक उप-प्रकार

इसलिए है, यह डिस्पैच

के दोनों संस्करणों के लिए बिल फिट बैठता है

सूप के बाद से हासा, HasB की एक उप प्रकार नहीं है , या हैससी, यह भी नहीं कह सकता कि एक संस्करण दूसरे की तुलना में अधिक "विशिष्ट" है।

इसलिए आपको त्रुटि ठीक से मिल जाएगी।

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

+0

उत्कृष्ट स्पष्टीकरण :) +1 –

10

ध्यान दें कि त्रुटि जेनरिक से संबंधित नहीं है, यदि आप इंटरफेस का उपयोग एक ही परिणाम मिलता है और एक प्रकार चौराहे है:

public class AA { 

    interface XX{}; 
    interface YY{}; 

    public void doSomething(XX x){} 
    public void doSomething(YY x){} 

    class XY implements XX,YY{ 

    } 

    public void runner(){ 
     doSomething(new XY()); 
    } 
} 

आप "DoSomething" में एक ही त्रुटि मिलती है, संकलक नहीं कर सकते अस्पष्टता को हल करें। क्या आप एक्सएक्स या वाई वाई के रूप में व्याख्या करना चाहते हैं? आपको इसे एक कलाकार के साथ निर्दिष्ट करना होगा। लेकिन यदि आपके पास पदानुक्रम है, जैसे "वाई वाई एक्सएक्स बढ़ाता है" और "एक्सवाई लागू करता है", तो कंपाइलर कॉल करने के लिए सही विधि का अनुमान लगा सकता है।

demo.<AlphabetSoup>dispatch(new AlphabetSoup()); 

या फोन के साथ सूप संस्करण:

1

ऐसा नहीं है कि आप अतिभारित dispatch विधि (मुझे लगता है कि कारण के लिए उरी upvoted) रखना चाहिए, लेकिन आप जेनेरिक वर्जन मजबूर कर सकते हैं कोशिश कर रहा द्वारा कहा जा

demo.dispatch((Soup) new AlphabetSoup()); 

हालांकि, इसके आसपास बेहतर तरीका है कि पहले स्थान पर dispatch विधि अधिभारित नहीं है।

void dispatchSoup(Soup soup); 
<T extends HasA & HasB & HasC> void dispatchLetters(T letters); 
2

मुझे एक बहुत ही सरल कार्यक्रम के साथ इस बारे में बताएं: विधि का सचित्र couse नीचे

कोड प्रकार संकलक त्रुटि के लिए अस्पष्ट है।

public class AmbiguousMethodOwner { 
      void ambiguousMethod(Comparable c){} 
      void ambiguousMethod(Serializable c){} 
      void test() { 
        ambiguousMethod("bar"); 
      } 
    } 

समस्या अब स्पष्ट है: के बाद से स्ट्रिंग दोनों तुलनीय और Serializable लागू करता है, संकलक पता नहीं कर सकते हैं कि कौन सी विधि आप कॉल करना चाहते हैं।

एक साधारण डाली समस्या का समाधान होगा:

ambiguousMethod ((तुलनीय) "बार");

http://www.javaneverdie.com/java/the-method-is-ambiguous-for-the-type/

हमारे मामले विधि प्रेषण में समस्या पैदा कर रही है। देखें

class AlphabetSoup implements Soup, HasA, HasB, HasC 

और

public void dispatch(Soup soup) 
public <T extends HasA & HasB & HasC> void dispatch(T letters) { 
अब अगर आप फोन dispatch(new AlphabetSoup()); संकलक के रूप में प्रेषण का कौन सा संस्करण बुलाया जाना चाहिए करने के लिए भ्रमित हो जाएगा

?

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