जावा पैरामीटर में पदोन्नति


20

मैंने इस स्निपेट पर ठोकर खाई:

public class ParamTest {
    public static void printSum(int a, double b) {
        System.out.println("In intDBL " + (a + b));
    }

    public static void printSum(long a, long b) {
        System.out.println("In long " + (a + b));
    }

    public static void printSum(double a, long b) {
        System.out.println("In doubleLONG " + (a + b));
    }

    public static void main(String[] args) {
        printSum(1, 2);
    }
}

यह एक संकलन त्रुटि के परिणामस्वरूप होगा:

त्रुटि: (15, 9) जावा: प्रिंटसुम का संदर्भ अस्पष्ट है दोनों विधि प्रिंटसम (int, double) ParamTest में और पद्धति PrintSum (लंबा, लंबा) ParamTest मैच में

यह कैसा अस्पष्ट है? क्या इस मामले में केवल दूसरे पैरामीटर को बढ़ावा नहीं दिया जाना चाहिए क्योंकि पहला पैरामीटर पहले से ही एक इंट है? इस मामले में पहले परम को बढ़ावा देने की आवश्यकता नहीं है?

यदि मैं किसी अन्य विधि को जोड़ने के लिए कोड को अपडेट करता हूं तो संकलन सफल होता है:

public static void printSum(int a, long b) {
    System.out.println(String.format("%s, %s ", a, b));
}

मुझे स्पष्ट करने के लिए विस्तार करें। नीचे दिए गए कोड में अस्पष्टता है:

public class ParamTest {

    public static void printSum(int a, double b) {
        System.out.println("In intDBL " + (a + b));
    }

    public static void printSum(long a, long b) {
        System.out.println("In long " + (a + b));
    }

    public static void main(String[] args) {
        printSum(1, 2);
    }
}

फिर नीचे दिए गए इस कोड से भी अस्पष्टता आती है:

public class ParamTest {

    public static void printSum(int a, double b) {
        System.out.println("In intDBL " + (a + b));
    }

    public static void printSum(double a, long b) {
        System.out.println("In doubleLONG " + (a + b));
    }

    public static void main(String[] args) {
        printSum(1, 2);
    }
}

हालांकि यह अस्पष्टता में परिणाम नहीं करता है:

public class ParamTest {

    public static void printSum(int a, double b) {
        System.out.println("In intDBL " + (a + b));
    }

    public static void printSum(long a, double b) {
        System.out.println("In longDBL " + (a + b));
    }

    public static void main(String[] args) {
        printSum(1, 2);
    }
}

2
कंपाइलर आपके कॉल प्रिंट को मैप कर सकता है (1, 2); या तो PrintSum (long a, long b) या printSum (int a, double b) इसलिए यह अस्पष्ट है। आपको स्पष्ट रूप से कंपाइलर का चयन इस प्रकार टाइप करके चुनने में मदद करना है: PrintSum (1, 2d)
रवींद्र रानवाला

6
आपने त्रुटि संदेश गलत लिखा है, और अंतर बहुत महत्वपूर्ण है। वास्तविक त्रुटि संदेश है: Error:(15, 9) java: reference to printSum is ambiguous both method printSum(int,double) in ParamTest and method printSum(long,long) in ParamTest match- यह वह विधि नहीं है जो अस्पष्ट है, यह उस पद्धति के लिए कॉल है जो अस्पष्ट है।
इरविन बोलविडेट

1
@ErwinBolwidt त्रुटि संदेश ग्रहण से था क्षमा करें, मुझे वहां गलत संदेश दिया गया था। वैसे भी, मैं अभी भी इसे समझ नहीं पाया हूं क्योंकि प्रिंटसुम (उदाहरण ए, लॉन्ग बी) को जोड़ना त्रुटि संदेश को हटा देता है।
riruzen

2
JLS-5.3 => यदि अभिव्यक्ति का प्रकार एक ढीला मंगलाचरण संदर्भ में अनुमत रूपांतरण द्वारा पैरामीटर के प्रकार में परिवर्तित नहीं किया जा सकता है, तो एक संकलन-समय त्रुटि होती है। संदर्भ के लिए लागू होने लगता है, लेकिन वास्तव में सरल नहीं है कि कैसे पता लगाएं। +1
नमन

1
हमें निश्चित रूप से इसके लिए एक विहित प्रश्न की आवश्यकता है: stackoverflow.com/… । "
मार्को 13

जवाबों:


17

मुझे लगता है कि यह JLS के विशिष्ट नियम के बारे में 15.12.2.5 के साथ कुछ करना है सबसे विशिष्ट विधि का चयन । यह प्रकट करता है की:

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

कैसे जावा सबसे विशिष्ट विधि चुनता है आगे पाठ द्वारा समझाया गया है:

अनौपचारिक अंतर्ज्ञान यह है कि एक विधि दूसरे की तुलना में अधिक विशिष्ट है यदि पहली विधि द्वारा संकलित किसी भी आह्वान को संकलन-समय त्रुटि के बिना दूसरे पर पारित किया जा सकता है। स्पष्ट रूप से टाइप किए गए लैम्ब्डा एक्सप्रेशन तर्क (715.27.1) या वैरिएबल एरिटी इनवोकेशन (ocation15.12.2.4) जैसे मामलों में, कुछ लचीलेपन को एक हस्ताक्षर को दूसरे में बदलने की अनुमति है।

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

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

public static void printSum(int a, double b) {
    System.out.println("In intDBL " + (a + b));
} // int, double cannot be passed to long, long or double, long without error

public static void printSum(long a, long b) {
    System.out.println("In long " + (a + b));
} // long , long cannot be passed to int, double or double, long without error

public static void printSum(double a, long b) {
    System.out.println("In doubleLONG " + (a + b));
} // double, long cannot be passed to int, double or long, long without error

चौथा तरीका अस्पष्टता को ठीक करता है क्योंकि यह सबसे विशिष्ट होने के लिए आवश्यक स्थिति को पूरा करता है

public static void printSum(int a, long b) {
    System.out.println(String.format("%s, %s ", a, b));
}

अर्थात, (int, long) संकलन त्रुटियों के बिना (int, double), (long, long), या (double, long) को पास किया जा सकता है।


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

धन्यवाद! मैंने इसके साथ (डबल, इंट) बनाम (डबल, लॉन्ग) की कोशिश की और इसने वास्तव में अस्पष्टता को स्पष्ट किया, फिर (डबल, इंट) बनाम (लॉन्ग, डबल) उम्मीद के मुताबिक अस्पष्ट था।
बजे .:

7

यह वास्तव में एक बहुत ही दिलचस्प सवाल है। चलिए जावा लैंग्वेज स्पेसिफिकेशन स्टेप बाई स्टेप देखते हैं।

  1. जब कंपाइलर संभावित रूप से लागू तरीकों की पहचान करने की कोशिश कर रहा है, तो पहली चीज जो सख्त मंगलाचरण द्वारा लागू की जाती है, वह है ।

  2. आपके मामले में ऐसी कोई विधि नहीं है, इसलिए अगला कदम लूज़ इनवोकेशन द्वारा लागू विधियों को खोजना है

  3. इस बिंदु पर सभी विधियाँ मेल खाती हैं, इसलिए सबसे विशिष्ट विधि ( .215.12.2.5 ) उन तरीकों के बीच चुनी जाती है जो ढीले आह्वान द्वारा लागू होती हैं।

यह एक महत्वपूर्ण क्षण है, तो आइए इसे करीब से देखें।

एक लागू विधि m1 एक और लागू विधि m2 की तुलना में अधिक विशिष्ट है, तर्क अभिव्यक्ति e1, ..., ek के साथ एक आह्वान के लिए, यदि निम्न में से कोई भी सत्य है:

(हम केवल निम्नलिखित मामले में रुचि रखते हैं):

  • एम 2 सामान्य नहीं है, और एम 1 और एम 2 सख्त या ढीले मंगलाचरण द्वारा लागू होते हैं, और जहां एम 1 में औपचारिक पैरामीटर प्रकार एस 1, ..., एसएन और एम 2 में औपचारिक पैरामीटर प्रकार टी 1, ..., टीएन है, टाइप सी अधिक है सभी i (1 ≤ i n n, n = k) के लिए तर्क ei के लिए ति से अधिक।

सीधे शब्दों में कहें, एक विधि अधिक विशिष्ट है यदि इसके सभी प्रकार के पैरामीटर अधिक विशिष्ट हैं । तथा

S <: T ( .104.10 ) यदि किसी प्रकार की अभिव्यक्ति के लिए टाइप T से अधिक टाइप S विशिष्ट है ।

अभिव्यक्ति का S <: Tमतलब है कि Sइसका एक उपप्रकार है T। प्राथमिकताओं के लिए हमारे पास निम्नलिखित संबंध हैं:

double > float > long > int

तो आइए अपने तरीकों को देखें और देखें कि कौन सा दूसरों की तुलना में अधिक विशिष्ट है।

public static void printSum(int a, double b) {  // method 1
    System.out.println("In intDBL " + (a + b));
}

public static void printSum(double a, long b) { // method 2
    System.out.println("In doubleLONG " + (a + b));
}

इस उदाहरण में विधि 1 का पहला पैरामीटर स्पष्ट रूप से विधि 2 के पहले पैरामीटर से अधिक विशिष्ट है (यदि आप उन्हें पूर्णांक मानों के साथ कहते हैं printSum(1, 2))। लेकिन विधि 2 के लिए दूसरा पैरामीटर अधिक विशिष्ट है , क्योंकि long < double। इसलिए इनमें से कोई भी तरीका दूसरे की तुलना में अधिक विशिष्ट नहीं है। इसीलिए आपके यहाँ अस्पष्टता है।

निम्नलिखित उदाहरण में:

public static void printSum(int a, double b) { // method 1
    System.out.println("In intDBL " + (a + b));
}

public static void printSum(long a, double b) { // method 2
    System.out.println("In longDBL " + (a + b));
}

विधि 1 का पहला पैरामीटर प्रकार विधि 2 में एक से अधिक विशिष्ट है, क्योंकि int < longऔर दूसरा पैरामीटर प्रकार उन दोनों के लिए समान है, इसीलिए विधि 1 चुना गया है।


मैंने आपके उत्तर को अस्वीकार नहीं किया, लेकिन यह उत्तर स्पष्ट नहीं करता है कि (int, double) स्पष्ट रूप से (लंबे, लंबे) के साथ अस्पष्ट है (int, double) पहले पैरामीटर के संबंध में अधिक विशिष्ट होना चाहिए।
riruzen

3
@riruzen यह व्याख्या करता है: doubleसे अधिक विशिष्ट नहीं है long। और विधि के लिए सभी प्रकार के मापदंडों को चुना जाना चाहिए और अधिक विशिष्ट होना चाहिए: प्रकार I के लिए तर्क ई के लिए Ti से अधिक विशिष्ट है I (1 (i, n, n = k)
Kirill Simonov

यह
टी

0

क्योंकि java में int value को दोगुना भी माना जा सकता है। साधन double a = 3वैध है और लंबे समय से long b = 3ऐसा ही है इसलिए यह एक अस्पष्टता पैदा कर रहा है। आप कॉल करें

printSum(1, 2);

सभी तीन तरीकों के लिए भ्रामक है, क्योंकि ये तीनों वैध हैं:

int a = 1;
double b =1;
long c = 1;

आप एल को अंत में रख सकते हैं, यह निर्दिष्ट करने के लिए कि यह लंबा मूल्य है। उदाहरण के लिए:

printSum(1L, 2L);

डबल के लिए आपको इसे बदलने की आवश्यकता है:

printSum((double)1, 2L);

@Erwin बोलवेट की टिप्पणी भी पढ़ें


हाँ कंपाइलर सभी 3 तरीकों के लिए उलझन में है, पहले कंपाइलर सटीक प्रकार के लिए दिखता है और यदि यह नहीं मिलता है तो संगत प्रकार खोजने की कोशिश करें, और इस मामले में सभी संगत हैं।
एक और कोडर

2
यदि मेरे पास 3 के बजाय 4 विधि घोषणाएं हैं, तो अस्पष्टता बंद हो जाती है: सार्वजनिक स्थैतिक शून्य प्रिंटसम (int a, double b) सार्वजनिक स्थैतिक शून्य प्रिंटसम (int a, long b) सार्वजनिक स्थैतिक शून्य प्रिंटसम (long a, long b) सार्वजनिक स्थैतिक शून्य प्रिंटसम (डबल ए, लॉन्ग बी) इसलिए जब तक मैं आपके उत्तर से सहमत हूं, तब भी यह प्रश्न का उत्तर नहीं देता है। अगर मैं गलत नहीं हूं तो सटीक प्रकार उपलब्ध नहीं होने पर जावा स्वचालित प्रकार का प्रचार करता है। मुझे अभी समझ में नहीं आया कि यह उन लोगों के साथ क्यों अस्पष्ट हो जाता है
riruzen
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.