java कंपाइलर त्रुटि: अस्पष्ट कॉल करने के संदर्भ




methods polymorphism (5)

यदि जावा भाषा विशिष्टता से हम एक से अधिक विधि लागू हो सकते हैं, तो हम सबसे विशिष्ट विधि का चयन करते हैं , अनुच्छेद 15.12.2.5 :

m नामक एक परिवर्तनीय धैर्य सदस्य विधि एक ही नाम के किसी अन्य परिवर्तनीय धैर्य सदस्य विधि से अधिक विशिष्ट है यदि (या <: means subtyping ):

  1. एक सदस्य विधि में एन पैरामीटर होते हैं और दूसरे के पास के पैरामीटर होते हैं, जहां n ≥ k, और:
    • पहली सदस्य विधि के पैरामीटर के प्रकार टी 1, ..., टीएन -1, टीएन [] हैं। ( हमारे पास केवल एक T_n है [], जो इंटीजर है [], n = 1 )
    • अन्य विधि के पैरामीटर के प्रकार यू 1, ..., यूके -1, यूके [] हैं। ( फिर केवल एक पैरामीटर, जो int [], k = 1 है )
    • यदि दूसरी विधि जेनेरिक है तो आर 1 दें ... आरपी (पी ≥ 1) इसके प्रकार के पैरामीटर हो, बीएल को आरएल (1 ≤ एल ≤ पी) की घोषित सीमा हो, चलो ए 1 ... एपी अनुमानित प्रकार के तर्क हो (§15.12.2.7) प्रारंभिक बाधाओं के तहत इस आमंत्रण के लिए टीआई << उई (1 ≤ i ≤ के -1) और टीआई << ब्रिटेन (के ≤ i ​​≤ एन), और सी = उई [आर 1 = ए 1, चलो। .., आरपी = एपी] (1 ≤ i ≤ के)। ( विधि सामान्य नहीं है )
    • अन्यथा, सी = उई (1 ≤ i ≤ के) दें। ( एस 1 = int [] )
    • सभी जे से 1 से के -1 तक, टीजे <: एसजे, और, ( यहां कुछ भी नहीं )
    • सभी जे से के लिए एन, टीजे <: स्क, और, ( टी 1 <: एस 1, इंटीजर [] <: int [] ) की तुलना करें
    • यदि दूसरी विधि उपरोक्त वर्णित एक सामान्य विधि है, तो अल <: Bl [R1 = A1, ..., आरपी = एपी] (1 ≤ एल ≤ पी)। ( विधि सामान्य नहीं है )

यद्यपि आदिम int इंटीजर रैपर करने के लिए autoboxed है, int[] Integer[] लिए autoboxed नहीं है, पहली स्थिति की तुलना में नहीं है।

दूसरी स्थिति लगभग एक ही है।

ऐसी अन्य स्थितियां भी हैं जो पकड़ नहीं लेती हैं, और फिर जेएलएस के कारण:

हम कहते हैं कि विधि आमंत्रण संदिग्ध है, और एक संकलन-समय त्रुटि होती है।

मामला एक

static void call(Integer i) {
    System.out.println("hi" + i);
}

static void call(int i) {
    System.out.println("hello" + i);
}

public static void main(String... args) {
    call(10);
}

केस 1 का आउटपुट: हैलो 10

केस 2

static void call(Integer... i) {
    System.out.println("hi" + i);
}

static void call(int... i) {
    System.out.println("hello" + i);
}

public static void main(String... args) {
    call(10);
}

reference to call ambiguous संकलन त्रुटि reference to call ambiguous दिखाता reference to call ambiguous । लेकिन, मैं समझने में असमर्थ था। क्यूं कर ? लेकिन, जब मैंने Case 2 से किसी भी call() विधियों पर टिप्पणी की, तो यह ठीक काम करता है। क्या कोई मुझे समझने में मदद कर सकता है, यहाँ क्या हो रहा है?


ऐसा लगता है कि यह बग # 6886431 से संबंधित है, जो ओपनजेडीके 7 में तय किया गया है।

नीचे बग विवरण है,

बग विवरण:

निम्नलिखित अधिभारित हस्ताक्षरों के साथ एक विधि का आह्वान करते समय, मुझे एक अस्पष्टता त्रुटि की उम्मीद है (तर्क मानते हुए दोनों के साथ संगत हैं):

int f(Object... args);
int f(int... args);

जावैक दूसरे की तुलना में दूसरे को अधिक विशिष्ट मानता है। यह व्यवहार समझदार है (मैं इसे पसंद करता हूं), लेकिन जेएलएस (15.12.2) के साथ असंगत है।


सबसे विशिष्ट विधि को ढूँढना जावा भाषा विशिष्टता (जेएलएस) में एक बहुत ही औपचारिक तरीके से परिभाषित किया गया है। मैंने औपचारिक सूत्रों को यथासंभव हटाने की कोशिश करते समय लागू मुख्य वस्तुओं के नीचे निकाला है।

संक्षेप में आपके प्रश्नों पर लागू होने वाली मुख्य वस्तुएं हैं:

  • जेएलएस 15.12.2 : आपका उपयोग मामला चरण 3 के अंतर्गत आता है:

तीसरा चरण (§15.12.2.4) परिवर्तनीय धर्मार्थ विधियों, मुक्केबाजी, और अनबॉक्सिंग के साथ जोड़ा जाने के लिए ओवरलोडिंग की अनुमति देता है।

  • फिर जेएलएस 15.12.2.4 मूल रूप से निर्धारित करता है कि दोनों विधि लागू हैं, क्योंकि 10 को Integer... या एक int... दोनों में परिवर्तित किया जा सकता है int... अब तक सब ठीक है। और अनुच्छेद निष्कर्ष निकाला है:

सबसे विशिष्ट विधि (§15.12.2.5) लागू चर-arity विधियों के बीच चुना जाता है।

  • जो हमें जेएलएस 15.12.2.5 में लाता है। यह अनुच्छेद उन स्थितियों को देता है जिनके अंतर्गत एक धर्मार्थ विधि m(a...) और धर्मार्थ विधि m(b...) से अधिक विशिष्ट है। आपके उपयोग मामले में एक पैरामीटर और कोई जेनेरिक के साथ, यह नीचे उबलता है:

m(a...) m(b...) से अधिक विशिष्ट है m(b...) iif a <: b , जहां <: मतलब is a subtype of

ऐसा होता है कि int Integer का एक उप प्रकार नहीं है और Integer int उप-प्रकार नहीं है।

जेएलएस भाषा का उपयोग करने के लिए, दोनों call विधियां इसलिए अधिकतम विशिष्ट हैं (कोई विधि दूसरे की तुलना में अधिक विशिष्ट नहीं है)। इस मामले में, वही पैराग्राफ निष्कर्ष निकाला है:

  • यदि सभी अधिकतम विशिष्ट तरीकों में ओवरराइड-समतुल्य (§8.4.2) हस्ताक्षर हैं [...] => आपके मामले में नहीं, क्योंकि कोई जेनेरिक शामिल नहीं है और इंटीजर और int अलग-अलग पैरामीटर हैं
  • अन्यथा, हम कहते हैं कि विधि आमंत्रण संदिग्ध है, और एक संकलन-समय त्रुटि होती है।

ध्यान दें

यदि आपने Integer... प्रतिस्थापित किया है Integer... long... उदाहरण के लिए, आपके पास int <: long और सबसे विशिष्ट विधि call(int...) * होगी।
इसी प्रकार, यदि आपने int... Number... प्रतिस्थापित किया है, तो call(Integer...) विधि सबसे विशिष्ट होगी।

* वास्तव में जावा 7 से पहले जेडीके में एक बग था जो उस स्थिति में एक अस्पष्ट कॉल दिखाएगा


इस सवाल को कई बार पहले से ही पूछा जा चुका है । मुश्किल हिस्सा यह है कि f(1, 2, 3) स्पष्ट रूप से int पास कर रहा है, तो संकलक f(int...) संस्करण क्यों नहीं चुन सकता है? उत्तर जेएलएस में कहीं झूठ बोलना चाहिए, जिसे मैं अपने सिर खरोंच कर रहा हूं

§15.12.2.4 के अनुसार, दोनों विधियां लागू चर-धर्मार्थ विधि हैं , इसलिए अगला चरण सबसे विशिष्ट पहचानने वाला है।

अनौपचारिक रूप से, §15.12.2.5 उप प्रकार परीक्षण टी i <: एस मैं एफ 1 (टी 1 , .. टी एन ) और एफ 2 (एस 1 , .. एस एन ) के बीच लक्ष्य विधि की पहचान करने के लिए औपचारिक मानकों का उपयोग करता है, और चूंकि वहां है Integer और int बीच कोई उपप्रकार संबंध नहीं, कोई भी जीतता नहीं है , क्योंकि न तो int:> पूर्णांक और न ही पूर्णांक:> int । अनुच्छेद के अंत में कहा गया है:

उपरोक्त स्थितियां एकमात्र परिस्थितियां हैं जिनके तहत एक विधि दूसरे की तुलना में अधिक विशिष्ट हो सकती है। [...]

एक विधि एम 1 किसी अन्य विधि m2 की तुलना में सख्ती से अधिक विशिष्ट है यदि केवल और यदि एम 1 एम 2 से अधिक विशिष्ट है और एम 2 एम 1 से अधिक विशिष्ट नहीं है।

एक विधि को विधिवत आमंत्रण के लिए अधिकतम रूप से विशिष्ट कहा जाता है यदि यह सुलभ और लागू होता है और कोई अन्य विधि लागू नहीं होती है जो सुलभ और सुलभ होती है जो सख्ती से अधिक विशिष्ट होती है।

यह संभव है कि कोई विधि सबसे विशिष्ट नहीं है, क्योंकि दो या दो से अधिक विधियां हैं जो अधिकतम विशिष्ट हैं। इस मामले में:

  1. [...]

  2. अन्यथा, हम कहते हैं कि विधि आमंत्रण संदिग्ध है, और एक संकलन-समय त्रुटि होती है।

गिलद ब्राचा द्वारा एक ब्लॉग पोस्ट संलग्न (प्रदर्शन 2 देखें), बदले में @ जयमोना के जवाब से बग रिपोर्ट में जुड़ा हुआ है।


जेएलएस 15.12.2.2 से

जेएलएस 15.12.2.2 सबसे विशिष्ट विधि चुनें

IIF एक से अधिक विधि घोषणा एक विधि आमंत्रण के लिए सुलभ और लागू दोनों है, रन-टाइम विधि प्रेषण के लिए वर्णनकर्ता प्रदान करने के लिए एक को चुनना आवश्यक है। जावा प्रोग्रामिंग भाषा नियम का उपयोग करती है कि सबसे विशिष्ट विधि चुना जाता है। अनौपचारिक अंतर्ज्ञान यह है कि एक विधि घोषणा किसी अन्य की तुलना में अधिक विशिष्ट होती है यदि पहली विधि द्वारा संभाला गया कोई भी आमंत्रण किसी अन्य को संकलित-समय प्रकार त्रुटि के बिना पारित किया जा सकता है।

इन तरीकों में से कोई भी दूसरे को पारित नहीं किया जा सकता है (int [] और इंटीजर [] से संबंधित नहीं हैं) इसलिए कॉल संदिग्ध है





boxing