2017-10-29 53 views
5
public class Base { 

    <T> List<? extends Number> f1() {return null;} 
    List<? extends Number>  f2() {return null;} 
    <T extends Number> List<T> f3() {return null; } 
} 

class Derived extends Base { 

    List<String> f1() {return null;} // compiles fine !!! 
    List<String> f3() {return null; } // compiles fine !!! 

    // compile ERR: return type is incompatible with Base.f2() 
    List<String> f2() {return null;} 
} 

क्यों अधिभावी तरीकों f1() और f3() व्युत्पन्न वर्ग में की परिभाषा व्युत्पन्न वर्ग (जो त्रुटि संकलन "वापसी प्रकार देता में f2() विधि अधिभावी की परिभाषा की तरह, कोई संकलन त्रुटि दिखा सकते हैं बेस के साथ असंगत है। एफ 2() ")?क्यों गैर-जेनेरिक एक सामान्य विधि को ओवरराइड करते समय subsignature और अनचेक नियम रिटर्न प्रकारों पर इस तरह काम करते हैं?

जेएलएस में सब्सिनेचर ओवरराइड नियम गैर-सामान्य होने के लिए ओवरराइडिंग विधि (व्युत्पन्न कक्षा में) की अनुमति देता है, जबकि ओवरराइड विधि (बेस क्लास में) सामान्य है।

अनचेक ओवरराइड नियम बेस क्लास में List<T> के बजाय उपclass List<String> में रिटर्न प्रकार बनाने की अनुमति देता है।

लेकिन मैं नीचे व्यवहार में अंतर की व्याख्या नहीं कर सकते हैं, और मुझे समझ नहीं आता क्यों व्युत्पन्न वर्ग में f1() और f3() अधिभावी परिभाषाएँ सफलतापूर्वक संकलन (ग्रहण, SE8 पर), अनदेखी प्रतिबंध के लिए घिरे प्रकार पैरामीटर द्वारा लगाए गए f3() और f1() के लिए बाध्य वाइल्डकार्ड द्वारा!

पीएस मेरा अनुमान - व्युत्पन्न कंपाइलर में f1() और f3() में दोनों विधियों को केवल "कच्ची" सूची लौटने के रूप में व्यवहार किया जाता है - कंपाइलर पहले मिटा देता है (इस पल में केवल व्युत्पन्न में !?) पहले, और फिर इन मिटाए गए तरीकों की तुलना बेरोजगार में बेकार (अब तक) आधार में तरीकों। अब अनचेक ओवरराइडिंग नियम ठीक है (और सीमाओं की जांच करने की कोई आवश्यकता नहीं है - यह केवल असंभव है), संकलक निर्णय लेता है कि यह सही ओवरराइडिंग और संकलन आगे जाता है ... और बेस.एफ 1() और बेस में संकलन जेनरिक के अंत में कहीं .f3() भी मिटा दिया :))

This SO answer इस विषय पर विचार भी जोड़ता है।

उत्तर

3

आपकी घोषणा f1 और f3 ओवरराइड सामान्य नहीं हैं, मूल घोषणा सामान्य होने के बावजूद। संकलन ओवरराइड के रिटर्न प्रकार को मूल रिटर्न प्रकारों से अलग करने की अनुमति देता है क्योंकि उनके पास एक ही प्रकार का एरर होता है (List)। मैं सोचता हूं जो JLS 8.4.5 से मिलता है, हालांकि स्पष्ट रूप से मुझे इस बात का थोड़ा सा भ्रमित लगता है।

आप फिर से सामान्य हो ओवरराइड को बदलते हैं:

<T> List<String> f1() {return null;} 
<T extends Number> List<String> f3() {return null; } 

... तो दोनों संकलन करने में विफल:

error: <T#1>f1() in Derived cannot override <T#2>f1() in Base 
    <T> List<String> f1() {return null;} 
        ^
    return type List<String> is not compatible with List<? extends Number> 
    where T#1,T#2 are type-variables: 
    T#1 extends Object declared in method <T#1>f1() 
    T#2 extends Object declared in method <T#2>f1() 

error: <T#1>f3() in Derived cannot override <T#2>f3() in Base 
    <T extends Number> List<String> f3() {return null; } 
            ^
    return type List<String> is not compatible with List<T#1> 
    where T#1,T#2 are type-variables: 
    T#1 extends Number declared in method <T#1>f3() 
    T#2 extends Number declared in method <T#2>f3() 

ध्यान दें कि यहां तक ​​कि अपने मूल कोड में, javac मुद्दों एक चेतावनी के आसपास असुरक्षित रूपांतरण, और यदि आप -Xlint:unchecked का उपयोग करते हैं तो यह विवरण देता है:

return type requires unchecked conversion from List<String> to List<? extends Number> 
return type requires unchecked conversion from List<String> to List<T> 
संबंधित मुद्दे