2009-02-01 23 views
31

मैंने आज देखा कि ऑटो-मुक्केबाजी कभी-कभी विधि अधिभार रिज़ॉल्यूशन में अस्पष्टता का कारण बन सकती है।ऑटोबॉक्सिंग जावा में अस्पष्ट कुछ कॉल क्यों करता है?

public class Test { 
    static void f(Object a, boolean b) {} 
    static void f(Object a, Object b) {} 

    static void m(int a, boolean b) { f(a,b); } 
} 

जब संकलित है, यह निम्न त्रुटि का कारण बनता है: सबसे सरल उदाहरण यह प्रतीत होता है

Test.java:5: reference to f is ambiguous, both method 
    f(java.lang.Object,boolean) in Test and method 
    f(java.lang.Object,java.lang.Object) in Test match 

static void m(int a, boolean b) { f(a, b); } 
           ^

इस त्रुटि को ठीक कर तुच्छ है:

static void m(int a, boolean b) { f((Object)a, b); } 
: बस स्पष्ट ऑटो मुक्केबाजी का उपयोग

जो अपेक्षित रूप से पहले अधिभार को सही ढंग से कॉल करता है।

तो ओवरलोड रिज़ॉल्यूशन क्यों विफल हुआ? संकलक ऑटो-बॉक्स को पहला तर्क क्यों नहीं मिला, और सामान्य रूप से दूसरे तर्क को स्वीकार क्यों किया? मुझे ऑटो-मुक्केबाजी का स्पष्ट रूप से अनुरोध क्यों करना पड़ा?

उत्तर

31

जब आप अपने आप वस्तु को पहला तर्क डाली, संकलक autoboxing (JLS3 15.12.2) का उपयोग किए बिना विधि मिलान हो जाएगा:

The first phase (§15.12.2.2) performs overload resolution without permitting boxing or unboxing conversion, or the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the second phase.

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

The second phase (§15.12.2.3) performs overload resolution while allowing boxing and unboxing, but still precludes the use of variable arity method invocation.

क्यों, दूसरे चरण में, संकलक दूसरी विधि का चयन नहीं करता है क्योंकि बूलियन तर्क का कोई autoboxing आवश्यक है? चूंकि इसे दो मिलान करने के तरीकों के बाद पाया गया है, केवल उप-प्रकार रूपांतरण का उपयोग दोनों की सबसे विशिष्ट विधि निर्धारित करने के लिए किया जाता है, भले ही किसी भी मुक्केबाजी या अनबॉक्सिंग को पहले स्थान पर मिलान करने के लिए किया गया हो (§15.12.2.5)।

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

public class Test { 
    static void f(Object a, boolean b) {} 
    static void f(int a, Object b) {} 

    static void m(int a, boolean b) { f(a, b); } // ambiguous 
} 

याद रखें कि एक मिलान विधि को चुनने के लिए एल्गोरिथ्म (संकलन-बार का चरण 2) तय की और JLS में वर्णित है। चरण 2 में एक बार कोई चुनिंदा ऑटोबॉक्सिंग या अनबॉक्सिंग नहीं होती है। कंपाइलर सभी उन विधियों को सुलभ करेगा (इन मामलों में दोनों विधियों) और लागू (दो तरीकों से), और फिर केवल मुक्केबाजी/अनबॉक्सिंग को देखे बिना सबसे विशिष्ट विकल्प चुनता है, जो यहां अस्पष्ट है।

+1

धन्यवाद @eljenso। यह संकलक के मुद्दे को स्पष्ट करता है, लेकिन फिर यह मुझे आश्चर्यचकित करता है कि दूसरे चरण को क्यों परिभाषित किया गया है। क्या इसे "मुक्केबाजी/अनबॉक्सिंग रूपांतरणों की कम से कम संभव संख्या" के साथ संशोधित नहीं किया जा सकता है? –

+0

उत्कृष्ट जवाब! –

+0

ठीक है, धन्यवाद @eljenso! मैं मानता हूं कि, आपके उदाहरण में, कॉल संदिग्ध है। मुझे लगता है कि दो अधिभारों में मुक्केबाजी रूपांतरणों की समान संख्या होगी, इसलिए कॉल वास्तव में संदिग्ध है। लेकिन (जेएलएस के बावजूद), मुझे अपना उदाहरण अस्पष्ट नहीं दिख रहा है। तुम क्या सोचते हो? –

2

So why did the overload resolution fail? Why didn't the compiler auto-box the first argument, and accept the second argument normally? Why did I have to request auto-boxing explicitly?

यह सामान्य रूप से दूसरे तर्क को स्वीकार नहीं करता था। याद रखें कि "बुलियन" को ऑब्जेक्ट में भी बॉक्स किया जा सकता है। आप स्पष्ट रूप से ऑब्जेक्ट के लिए बूलियन तर्क भी डाल सकते थे और यह काम करता।

+0

धन्यवाद @ केविन। हाँ, मैं स्पष्ट रूप से इसे बॉक्स कर सकता था, लेकिन मैंने नहीं किया। तो यह सबसे विशिष्ट अधिभार क्यों नहीं चुना, जो इस मामले में पहला है? –

+0

क्योंकि संकलक के पास आपके लिए यह निर्णय लेने के लिए पर्याप्त जानकारी नहीं थी। * दोनों * विधियों को लागू किया गया क्योंकि बूलियन को ऑब्जेक्ट – Kevin

+0

पर बॉक्स किया जा सकता है, मुझे नहीं लगता कि यह प्रश्न का उत्तर देता है। जब कई विधियां लागू होती हैं, तो जिसकी आवश्यकता कम से कम चौड़ाई रूपांतरण की आवश्यकता होती है स्वचालित रूप से चुनी जाती है। आपको केवल अस्पष्टता त्रुटि मिलती है जब कई विधियों को "चौड़ाई" की समान संख्या की आवश्यकता होती है। मेरा अनुमान है कि मुक्केबाजी को चौड़ा करने के रूप में नहीं माना जाता है। – erickson

3

जब आप f (ए, बी) कहते हैं, तो संकलक उलझन में है कि किस संदर्भ में इसका संदर्भ होना चाहिए।

इसका कारण यह है एक एक पूर्णांक है, लेकिन तर्क चमें उम्मीद की एक वस्तु है। तो शिकायतकर्ता किसी ऑब्जेक्ट में को परिवर्तित करने का निर्णय लेता है। अब समस्या यह है कि, यदि किसी ऑब्जेक्ट में परिवर्तित किया जा सकता है, तो बी हो सकता है।

इसका मतलब है कि फ़ंक्शन कॉल या तो परिभाषाओं का संदर्भ दे सकता है। यह कॉल संदिग्ध बनाता है।

जब आप मैन्युअल रूप से किसी ऑब्जेक्ट में कनवर्ट करते हैं, तो कंपाइलर केवल निकटतम मैच की तलाश करता है और फिर इसे संदर्भित करता है।

Why didn't the compiler select the function that can be reached by "doing the least possible number of boxing/unboxing conversions"?

निम्नलिखित मामले देखें:

f(boolean a, Object b) 
f(Object a , boolean b) 

अगर हम जैसे च फोन (एक बूलियन, बूलियन ख), जो समारोह उसका चयन करना चाहिए? यह अस्पष्ट अधिकार है? इसी तरह, यह बहुत जटिल हो जाएगा जब बहुत से तर्क मौजूद हैं। तो संकलक ने आपको इसके बजाय चेतावनी देना चुना।

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

+0

धन्यवाद @Niyaz। लेकिन यहां तक ​​कि अगर ए और बी वस्तुओं में परिवर्तित किया जा सकता है, तो यह आवश्यक नहीं है _। इसलिए, कंपाइलर (आईएमएचओ) को किसी ऑब्जेक्ट में कनवर्ट करना होगा, लेकिन बी के लिए इसे सबसे विशिष्ट ओवरलोड चुनना चाहिए, जो पहला है। इस तर्क के साथ क्या गलत है? –

+0

यदि दिए गए उदाहरण में कई और तर्क हैं, तो कंपाइलर "सबसे विशिष्ट अधिभार" का चयन कैसे करता है? यही दिक्कत है। – Niyaz

+0

नियाज़। यदि वह ऑब्जेक्ट में रहता है तो इससे क्या फर्क पड़ता है? दोनों कार्य ऑब्जेक्ट स्वीकार करते हैं। तो मैं वृत्ति से कहूंगा कि यह कोई बेहतर मैच नहीं बनाता है। –

4

कंपाइलर ऑटो-बॉक्स पहला तर्क था। एक बार ऐसा करने के बाद, यह दूसरा तर्क है जो संदिग्ध है, क्योंकि इसे या तो बूलियन या ऑब्जेक्ट के रूप में देखा जा सकता है।

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

+0

उस मामले में, एफ (ऑब्जेक्ट, बूलियन) अधिक "विशिष्ट" विधि नहीं होगी? –

+0

धन्यवाद @ बिल। @Zach ने उसी प्रश्न से पूछा जो मुझे दिमाग में था। –

+0

मैंने उस प्रश्न को कवर करने के लिए अपना जवाब संपादित किया। –

2

http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#20448

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

लोगों को अनुमान लगाने के बजाय क्या होगा, यह स्पष्ट और समझने योग्य चश्मे रखना बेहतर होगा।

+0

तो, यह "एक बार ऑटो-बॉक्स किए जाने के समान है, हम भी अन्य तर्कों के साथ गंदे जा सकते हैं" और "यदि कोई ऑटो-बॉक्स अभी तक नहीं हुआ है, तो हम दूसरों को भी ऑटोबॉक्स न करने का प्रयास करते हैं"? –

+0

धन्यवाद @iny। आज के लिए वोटों से बाहर होने के लिए मैं क्षमा चाहता हूं! –

+0

@ लिटब, हां जाहिर है। लेकिन मुझे आश्चर्य है कि वे "मुक्केबाजी/अनबॉक्सिंग रूपांतरणों की कम से कम संभव संख्या" करने का प्रयास क्यों नहीं कर रहे हैं। –

1

जावा कंपाइलर चरणों में अधिभारित विधियों और रचनाकारों को हल करता है। पहले चरण [§15.12.2.2] में, यह subtyping [§4.10] द्वारा लागू विधियों की पहचान करता है। इस उदाहरण में, न तो विधि लागू होती है, क्योंकि int ऑब्जेक्ट का उप-प्रकार नहीं है।

दूसरे चरण [§15.12.2.3] में, कंपाइलर विधि आमंत्रण रूपांतरण [§5.3] द्वारा लागू विधियों की पहचान करता है, जो ऑटोबॉक्सिंग और सबटाइपिंग का संयोजन है। Int तर्क को एक पूर्णांक में परिवर्तित किया जा सकता है, जो ऑब्जेक्ट का एक उप प्रकार है, दोनों ओवरलोड के लिए। बुलियन तर्क को पहले अधिभार के लिए कोई रूपांतरण की आवश्यकता नहीं होती है, और दूसरे के लिए ऑब्जेक्ट का एक उप प्रकार, बूलियन में परिवर्तित किया जा सकता है। इसलिए, दोनों चरण दूसरे चरण में लागू होते हैं।

चूंकि एक से अधिक विधि लागू होती हैं, इसलिए संकलक को यह निर्धारित करना होगा कि सबसे विशिष्ट [§15.12.2.5] कौन सा है। यह पैरामीटर प्रकारों की तुलना करता है, तर्क प्रकार नहीं, और यह उन्हें ऑटोबॉक्स नहीं करता है। ऑब्जेक्ट और बुलियन असंबद्ध प्रकार हैं, इसलिए उन्हें समान रूप से विशिष्ट माना जाता है। न तो विधि दूसरे की तुलना में अधिक विशिष्ट है, इसलिए विधि कॉल संदिग्ध है।

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

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