एकल अशक्त तर्क के साथ जावा varargs पद्धति को कॉल करना?


97

अगर मैं एक vararg जावा विधि है foo(Object ...arg)और मैं कॉल foo(null, null), मैं दोनों है arg[0]और arg[1]के रूप में nullहै। लेकिन अगर मैं फोन करता हूं foo(null), तो argवह अशक्त है। ये क्यों हो रहा है?

मैं कैसे बुलाना चाहिए fooऐसी है कि foo.length == 1 && foo[0] == nullहै true?

जवाबों:


95

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

आपके पास दो विकल्प हैं। स्पष्ट रूप से टाइप किए गए वैरिएबल का उपयोग करके विधि को कॉल या कॉल करने के लिए अशक्त रूप से कास्ट करें। नीचे दिए गए उदाहरण देखें:

public class Temp{
   public static void main(String[] args){
      foo("a", "b", "c");
      foo(null, null);
      foo((Object)null);
      Object bar = null;
      foo(bar);
   }

   private static void foo(Object...args) {
      System.out.println("foo called, args: " + asList(args));
   }
}

आउटपुट:

foo called, args: [a, b, c]
foo called, args: [null, null]
foo called, args: [null]
foo called, args: [null]

दूसरों के लिए उपयोगी होगा यदि आपने asListनमूने में विधि और इसके उद्देश्य को सूचीबद्ध किया था ।
अरुण कुमार

5
@ अरुणकुमार वर्ग asList()से एक स्थिर आयात है java.util.Arrays। मैंने सिर्फ यह माना कि यह स्पष्ट था। हालाँकि अब जब मैं इसके बारे में सोच रहा हूँ, तो मुझे शायद इसका उपयोग करना चाहिए था Arrays.toString()क्योंकि इसका एकमात्र कारण यह सूची में परिवर्तित हो जाता है, इसलिए यह सुंदर रूप से छपेगा।
माइक डेक

23

आपको एक स्पष्ट कलाकार चाहिए Object:

foo((Object) null);

अन्यथा तर्क को संपूर्ण सरणी माना जाता है जो कि वैरग का प्रतिनिधित्व करता है।


वास्तव में नहीं, मेरी पोस्ट देखें।
बुहके सिंडी

उफ़, यहाँ भी वही ... सॉरी, मिडनाइट ऑयल।
बुहके सिंडी

6

यह बताने के लिए एक टेस्ट केस:

एक vargg- लेने की विधि घोषणा के साथ जावा कोड (जो स्थिर होने के लिए होता है):

public class JavaReceiver {
    public static String receive(String... x) {
        String res = ((x == null) ? "null" : ("an array of size " + x.length));
        return "received 'x' is " + res;
    }
}

यह जावा कोड (एक JUnit4 परीक्षण मामला) ऊपर कहता है (हम परीक्षण मामले का उपयोग कुछ भी परीक्षण करने के लिए नहीं कर रहे हैं, बस कुछ उत्पादन उत्पन्न करने के लिए):

import org.junit.Test;

public class JavaSender {

    @Test
    public void sendNothing() {
        System.out.println("sendNothing(): " + JavaReceiver.receive());
    }

    @Test
    public void sendNullWithNoCast() {
        System.out.println("sendNullWithNoCast(): " + JavaReceiver.receive(null));
    }

    @Test
    public void sendNullWithCastToString() {
        System.out.println("sendNullWithCastToString(): " + JavaReceiver.receive((String)null));
    }

    @Test
    public void sendNullWithCastToArray() {
        System.out.println("sendNullWithCastToArray(): " + JavaReceiver.receive((String[])null));
    }

    @Test
    public void sendOneValue() {
        System.out.println("sendOneValue(): " + JavaReceiver.receive("a"));
    }

    @Test
    public void sendThreeValues() {
        System.out.println("sendThreeValues(): " + JavaReceiver.receive("a", "b", "c"));
    }

    @Test
    public void sendArray() {
        System.out.println("sendArray(): " + JavaReceiver.receive(new String[]{"a", "b", "c"}));
    }
}

JUnit परीक्षण की उपज के रूप में इसे चलाना:

sendNothing (): प्राप्त 'x' आकार 0 की एक सरणी है
sendNullWithNoCast (): प्राप्त 'x' शून्य है
sendNullWithCastToString (): प्राप्त 'x' आकार 1 की एक सरणी है
sendNullWithCastToArray (): प्राप्त 'x' शून्य है
sendOneValue (): प्राप्त 'x' आकार 1 की एक सरणी है
sendThreeValues ​​(): प्राप्त 'x' आकार 3 की एक सरणी है
sendArray (): प्राप्त 'x' आकार 3 की एक सरणी है

इसे और अधिक दिलचस्प बनाने के लिए, हम receive()ग्रूवी 2.1.2 से फ़ंक्शन को कॉल करें और देखें कि क्या होता है। यह पता चला है कि परिणाम समान नहीं हैं! हालांकि यह एक बग हो सकता है।

import org.junit.Test

class GroovySender {

    @Test
    void sendNothing() {
        System.out << "sendNothing(): " << JavaReceiver.receive() << "\n"
    }

    @Test
    void sendNullWithNoCast() {
        System.out << "sendNullWithNoCast(): " << JavaReceiver.receive(null) << "\n"
    }

    @Test
    void sendNullWithCastToString() {
        System.out << "sendNullWithCastToString(): " << JavaReceiver.receive((String)null) << "\n"
    }

    @Test
    void sendNullWithCastToArray() {
        System.out << "sendNullWithCastToArray(): " << JavaReceiver.receive((String[])null) << "\n"
    }

    @Test
    void sendOneValue() {
        System.out << "sendOneValue(): " + JavaReceiver.receive("a") << "\n"
    }

    @Test
    void sendThreeValues() {
        System.out << "sendThreeValues(): " + JavaReceiver.receive("a", "b", "c") << "\n"
    }

    @Test
    void sendArray() {
        System.out << "sendArray(): " + JavaReceiver.receive( ["a", "b", "c"] as String[] ) << "\n"
    }

}

यह एक JUnit परीक्षण के रूप में चलाने से जावा में बोल्ड में अंतर के साथ, निम्नलिखित पैदावार होती है।

sendNothing (): प्राप्त 'x' आकार 0 की एक सरणी है
sendNullWithNoCast (): प्राप्त 'x' शून्य है
sendNullWithCastToString (): प्राप्त 'x' शून्य है
sendNullWithCastToArray (): प्राप्त 'x' शून्य है
sendOneValue (): प्राप्त 'x' आकार 1 की एक सरणी है
sendThreeValues ​​(): प्राप्त 'x' आकार 3 की एक सरणी है
sendArray (): प्राप्त 'x' आकार 3 की एक सरणी है

यह पैरामीटर के बिना वैरिएडिक फ़ंक्शन को कॉल करने पर भी विचार करता है
बेबो

3

ऐसा इसलिए है क्योंकि एक varargs पद्धति को सरणी तत्वों की एक श्रृंखला के बजाय एक वास्तविक सरणी के साथ कहा जा सकता है। जब आप इसे अपने आप से अस्पष्ट प्रदान करते हैं null, यह मानता है कि nullयह एक है Object[]। इसे ठीक nullकरने के लिए कास्टिंग करना Object


1

मैं पसंद करता हूं

foo(new Object[0]);

अशक्त सूचक अपवादों से बचने के लिए।

आशा करता हूँ की ये काम करेगा।


14
ठीक है, अगर यह एक वैरग विधि है, तो बस इसे क्यों नहीं कहते हैं foo()?
BrainStorm.exe

@ BrainStorm.exe आपके उत्तर को उत्तर के रूप में चिह्नित किया जाना चाहिए। धन्यवाद।
एमडीपी

1

ऑर्डर ओवरलोडिंग रिज़ॉल्यूशन के लिए ऑर्डरिंग ( https://docs.oracle.com/javase/specs/jls/se11/html/jls-15.html#jls-15.12.2 ) है:

  1. पहले चरण में बॉक्सिंग या अनबॉक्सिंग रूपांतरण की अनुमति के बिना, या परिवर्तनशील एरिटी विधि मंगलाचरण का उपयोग किए बिना ओवरलोड रिज़ॉल्यूशन किया जाता है। यदि इस चरण के दौरान कोई लागू विधि नहीं मिलती है तो प्रसंस्करण दूसरे चरण में जारी रहता है।

    यह गारंटी देता है कि जावा एसई 5.0 से पहले जावा प्रोग्रामिंग भाषा में मान्य किसी भी कॉल को अस्पष्टता के तरीकों, निहित बॉक्सिंग और / या अनबॉक्सिंग के परिणाम के रूप में अस्पष्ट नहीं माना जाता है। हालांकि, एक वेरिएबल एरिटी मेथड (.48.4.1) की घोषणा किसी दिए गए मेथड इनविटेशन एक्सप्रेशन के लिए चुने गए तरीके को बदल सकती है, क्योंकि पहले चरण में एक वेरिएबल एरिटी मेथड को एक निश्चित एरिटी मेथड के रूप में माना जाता है। उदाहरण के लिए, एक वर्ग में एम (ऑब्जेक्ट ...) घोषित करना जो पहले से ही एम (ऑब्जेक्ट) घोषित करता है, एम (ऑब्जेक्ट) का कारण अब कुछ इनवोकेशन एक्सप्रेशन (जैसे m (null)) के लिए नहीं चुना जाएगा, जैसा कि m (ऑब्जेक्ट [] ) अधिक विशिष्ट है।

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

    यह सुनिश्चित करता है कि वैरिएबल एरिटी मेथड इनवोकेशन के माध्यम से एक विधि को कभी नहीं चुना जाता है यदि यह निश्चित एरिटी मेथड इनवोकेशन के माध्यम से लागू होता है।

  3. तीसरे चरण में ओवरलोडिंग को वैरिएबल एरिटी मेथड्स, बॉक्सिंग और अनबॉक्सिंग के साथ जोड़ा जा सकता है।

foo(null)पहले चरण में मैच foo(Object... arg)हुए arg = nullarg[0] = nullतीसरा चरण होगा, जो कभी नहीं होता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.