क्या मैं जावा में चर तर्कों के साथ एक विधि के तर्क के रूप में एक सरणी पास कर सकता हूं?


275

मैं एक समारोह बनाने में सक्षम होना चाहता हूँ जैसे:

class A {
  private String extraVar;
  public String myFormat(String format, Object ... args){
    return String.format(format, extraVar, args);
  }
}

यहां समस्या यह है कि args के रूप में व्यवहार किया जाता है Object[]विधि में myFormat, और इस तरह के लिए एक एकल तर्क है String.format, जबकि मैं चाहता हूँ हर एक, Objectमें argsएक नया तर्क के रूप में पारित होने के लिए। चूंकि String.formatचर तर्कों के साथ एक विधि भी है, यह संभव होना चाहिए।

यदि यह संभव नहीं है, तो क्या कोई विधि है String.format(String format, Object[] args) ? उस स्थिति में मैं एक नई सारणी का उपयोग extraVarकरने के लिए तैयार हो सकता हूं argsऔर इसे उस विधि से पास कर सकता हूं ।


8
मैं मदद नहीं कर सकता, लेकिन आश्चर्य है कि यह प्रश्न "यह वैध" प्रश्न है। क्या आपने अभी इसकी कोशिश नहीं की है? ज़्यादा मत पूछो, आप अपने आप को अच्छे से अधिक नुकसान पहुंचाएंगे।
कामशेतो

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

2
मैं वास्तव में विधि के लिए तर्क के रूप में सरणी आर्ग्स पास करने के इरादे से ऊपर कोड की कोशिश की। हालाँकि, मुझे महसूस नहीं हुआ कि मुझे पहले args में extraVar का इस्तेमाल करना चाहिए। जब आप जानते हैं कि चर तर्कों को एक सरणी (विधि के बाहर भी) के रूप में माना जाता है, तो यह निश्चित रूप से काफी तार्किक है।
user362382

जवाबों:


180

एक अंतर्निहित विधि function(Object... args) का प्रकार हैfunction(Object[] args) । सूर्य ने पीछे की अनुकूलता को बनाए रखने के लिए इस तरह से varargs जोड़ा।

तो आपको बस कॉल extraVarकरने argsऔर कॉल करने में सक्षम होना चाहिए String.format(format, args)


X[]एक विधि में टाइप का एक तर्क पारित करना x(X... xs)ग्रहण में निम्नलिखित चेतावनी देता है:Type X[] of the last argument to method x(X...) doesn't exactly match the vararg parameter type. Cast to X[] to confirm the non-varargs invocation, or pass individual arguments of type X for a varargs invocation.
ल्यूक हचिसन

318

हाँ, एक T...केवल एक के लिए एक कृत्रिम चीनी है T[]

JLS 8.4.1 प्रारूप पैरामीटर

किसी सूची में अंतिम औपचारिक पैरामीटर विशेष है; यह एक वैरिएबल एरिटी पैरामीटर हो सकता है , जो कि टाइप के बाद एलिप्सिस द्वारा दर्शाया गया है।

यदि अंतिम औपचारिक पैरामीटर प्रकार का एक वैरिएबल एरिटी पैरामीटर है T, तो यह प्रकार के एक औपचारिक पैरामीटर को परिभाषित करने के लिए माना जाता है T[]। विधि तो एक चर arity विधि है। अन्यथा, यह एक निश्चित विधि है। एक वैरिएबल एरिटी विधि के इनवॉइस में औपचारिक मापदंडों की तुलना में अधिक वास्तविक तर्क अभिव्यक्ति हो सकती है। सभी वास्तविक तर्क अभिव्यक्तियाँ जो कि वैरिएबल एरिटी पैरामीटर से पहले के औपचारिक मापदंडों के अनुरूप नहीं हैं, का मूल्यांकन किया जाएगा और एक सरणी में संग्रहीत परिणामों को विधि मंगलाचरण में पास किया जाएगा।

यहाँ एक उदाहरण दिया गया है:

public static String ezFormat(Object... args) {
    String format = new String(new char[args.length])
        .replace("\0", "[ %s ]");
    return String.format(format, args);
}
public static void main(String... args) {
    System.out.println(ezFormat("A", "B", "C"));
    // prints "[ A ][ B ][ C ]"
}

और हां, उपरोक्त mainविधि मान्य है, क्योंकि फिर से, String...बस है String[]। इसके अलावा, क्योंकि सरणियाँ सहसंयोजक हैं, एक एक String[]है Object[], इसलिए आप किसी भी ezFormat(args)तरह से कॉल कर सकते हैं ।

यह सभी देखें


वरगार्स गोचेज # 1: पासिंग null

कैसे varargs हल किया जाता है काफी जटिल है, और कभी-कभी यह उन चीजों को करता है जो आपको आश्चर्यचकित कर सकते हैं।

इस उदाहरण पर विचार करें:

static void count(Object... objs) {
    System.out.println(objs.length);
}

count(null, null, null); // prints "3"
count(null, null); // prints "2"
count(null); // throws java.lang.NullPointerException!!!

कैसे varargs हल कर रहे हैं के कारण, के साथ पिछले बयान का आह्वान objs = nullहै, जो निश्चित रूप से कारण होगा NullPointerExceptionसाथ objs.length। यदि आप nullएक varargs पैरामीटर में एक तर्क देना चाहते हैं , तो आप निम्न में से कोई एक कार्य कर सकते हैं:

count(new Object[] { null }); // prints "1"
count((Object) null); // prints "1"

संबंधित सवाल

निम्नलिखित में से कुछ प्रश्नों का एक नमूना है जो लोगों ने वैरग से निपटने के दौरान पूछे हैं:


वरर्ग गोच # 2: अतिरिक्त तर्क जोड़ रहा है

जैसा कि आपको पता चला है, निम्नलिखित "काम" नहीं करता है:

    String[] myArgs = { "A", "B", "C" };
    System.out.println(ezFormat(myArgs, "Z"));
    // prints "[ [Ljava.lang.String;@13c5982 ][ Z ]"

जिस तरह से varargs काम करता है, ezFormatवास्तव में 2 तर्क मिलते हैं, पहला एक होने का String[], दूसरा दूसरा होने का String। यदि आप वर्णों के लिए एक सरणी पास कर रहे हैं, और आप चाहते हैं कि इसके तत्वों को अलग-अलग तर्कों के रूप में मान्यता दी जाए, और आपको एक अतिरिक्त तर्क भी जोड़ना होगा, तो आपके पास अतिरिक्त तत्व को समायोजित करने वाला एक और सरणी बनाने के अलावा कोई विकल्प नहीं है ।

यहां कुछ उपयोगी सहायक विधियां दी गई हैं:

static <T> T[] append(T[] arr, T lastElement) {
    final int N = arr.length;
    arr = java.util.Arrays.copyOf(arr, N+1);
    arr[N] = lastElement;
    return arr;
}
static <T> T[] prepend(T[] arr, T firstElement) {
    final int N = arr.length;
    arr = java.util.Arrays.copyOf(arr, N+1);
    System.arraycopy(arr, 0, arr, 1, N);
    arr[0] = firstElement;
    return arr;
}

अब आप निम्नलिखित कर सकते हैं:

    String[] myArgs = { "A", "B", "C" };
    System.out.println(ezFormat(append(myArgs, "Z")));
    // prints "[ A ][ B ][ C ][ Z ]"

    System.out.println(ezFormat(prepend(myArgs, "Z")));
    // prints "[ Z ][ A ][ B ][ C ]"

Varargs gotchas # 3: प्राथमिकताओं की एक सरणी से गुजर रहा है

यह "काम" नहीं करता है:

    int[] myNumbers = { 1, 2, 3 };
    System.out.println(ezFormat(myNumbers));
    // prints "[ [I@13c5982 ]"

वैराग्य केवल संदर्भ प्रकारों के साथ काम करता है। ऑटोबॉक्सिंग आदिम की सरणी पर लागू नहीं होता है। निम्नलिखित कार्य:

    Integer[] myNumbers = { 1, 2, 3 };
    System.out.println(ezFormat(myNumbers));
    // prints "[ 1 ][ 2 ][ 3 ]"

2
ऑब्जेक्ट का उपयोग करना ... वैरिएड पैरामीटर अतिरिक्त हस्ताक्षर का उपयोग करना मुश्किल बनाता है क्योंकि संकलक उन हस्ताक्षरों के बीच अस्पष्टता की पहचान करता है जहां एक आदिम तर्क को ऑब्जेक्ट के लिए स्वत: स्फूर्त किया जा सकता है।
eel ghEEz

7
एक गायब हो गया गोचा है: यदि आपकी विधि में ऑब्जेक्ट का अंतिम परम है ... और आप उदाहरण के लिए इसे स्ट्रिंग [] पास करना कहते हैं। कंपाइलर को यह नहीं पता होता है कि आपका सरणी वैरग का पहला आइटम है या सभी वैरग के बराबर है। यह आपको चेतावनी देगा।
Snicolas

X[]एक विधि में टाइप का एक तर्क पारित करना x(X... xs)ग्रहण में निम्नलिखित चेतावनी देता है:Type X[] of the last argument to method x(X...) doesn't exactly match the vararg parameter type. Cast to X[] to confirm the non-varargs invocation, or pass individual arguments of type X for a varargs invocation.
ल्यूक हचिसन

23

किसी सरणी को पास करना ठीक है - वास्तव में यह एक ही चीज़ पर निर्भर करता है

String.format("%s %s", "hello", "world!");

के समान है

String.format("%s %s", new Object[] { "hello", "world!"});

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

देख


4

jasonmp85 एक अलग सरणी से गुजरने के बारे में सही है String.format। एक बार निर्मित एक सरणी का आकार नहीं बदला जा सकता है, इसलिए आपको मौजूदा एक को संशोधित करने के बजाय एक नया सरणी पास करना होगा।

Object newArgs = new Object[args.length+1];
System.arraycopy(args, 0, newArgs, 1, args.length);
newArgs[0] = extraVar; 
String.format(format, extraVar, args);

1

मैं एक ही मुद्दा रहा था।

String[] arr= new String[] { "A", "B", "C" };
Object obj = arr;

और फिर ओबीज को वैराग तर्क के रूप में पारित किया। इसने काम कर दिया।


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