Java, 3 จุดในพารามิเตอร์


คำตอบ:


987

หมายความว่าวัตถุสตริงเป็นศูนย์หรือมากกว่านั้น (หรืออาเรย์ของพวกเขา) อาจถูกส่งผ่านเป็นอาร์กิวเมนต์สำหรับวิธีการนั้น

ดูหัวข้อ "จำนวนข้อโต้แย้งโดยพลการ" ที่นี่: http://java.sun.com/docs/books/tutorial/java/javaOO/arguments.html#varargs

ในตัวอย่างของคุณคุณสามารถเรียกมันดังต่อไปนี้:

myMethod(); // Likely useless, but possible
myMethod("one", "two", "three");
myMethod("solo");
myMethod(new String[]{"a", "b", "c"});

หมายเหตุสำคัญ:อาร์กิวเมนต์ที่ส่งผ่านด้วยวิธีนี้จะเป็นอาร์เรย์เสมอแม้ว่าจะมีเพียงรายการเดียวก็ตาม ตรวจสอบให้แน่ใจว่าคุณปฏิบัติเช่นนั้นในร่างกายวิธี

หมายเหตุสำคัญ 2:อาร์กิวเมนต์ที่ได้รับ...จะต้องเป็นครั้งสุดท้ายในลายเซ็นวิธีการ ดังนั้นmyMethod(int i, String... strings)ก็โอเค แต่myMethod(String... strings, int i)ไม่เป็นไร

ขอบคุณ Vash สำหรับคำอธิบายในความคิดเห็นของเขา


112
คุณเข้าใจผิดว่า "หนึ่งหรือมากกว่านั้น" ด้วย varargs เราสามารถระบุ 0 หรือมากกว่าและสิ่งนี้จะต้องเป็นพารามิเตอร์สุดท้ายเสมอในวิธีการ วิธีการ x (String ... params) สามารถเรียกเป็น x () หรือวิธี y (String Pram, String ... params) สามารถเรียกเป็น y ("1")
Damian Leszczyński - Vash

2
ฉันหวังว่าจะใช้งานได้เช่นกัน myMethod ("หนึ่ง", "สอง", "สาม", สตริงใหม่ [] {"a", "b", "c" "}));
2sb

2
ทำไมคุณถึงได้รับอนุญาตให้กำหนดพารามิเตอร์เมธอด 0 นั่นน่าจะนำไปสู่ ​​ArrayIndexOutOfBoundsException ตอนนี้คุณต้องคำนึงถึงกรณีนั้นเสมอ
Olle Söderström

11
เพราะพวกมันเป็นตัวเลือก ขึ้นอยู่กับนักพัฒนาที่ตัดสินใจใช้อาร์กิวเมนต์ที่เป็นทางเลือกเพื่อใช้วิธีการที่เหมาะสมในการจัดการให้มีศูนย์หรือมากกว่านั้น
kiswa

@ OlleSöderströmอีกเหตุผลหนึ่งคือพารามิเตอร์ที่เป็นทางการจะถูกแปลงเป็นอาร์เรย์ในเวลารวบรวม นั่นหมายความว่าการผ่านอาร์เรย์จะให้ผลลัพธ์เดียวกัน ตั้งแต่ความยาวของอาร์เรย์ไม่เป็นที่รู้จักในเวลารวบรวมข้อ จำกัด someMethod(new SomeType[] { })ที่จะผ่านองค์ประกอบอย่างน้อยหนึ่งอาจจะข้ามโดยเพียงแค่โทร นั่นจะเป็นการแฮ็กใช่ไหม?
MC Emperor

124

คุณลักษณะนั้นเรียกว่าvarargsและเป็นคุณลักษณะที่นำมาใช้ใน Java 5 ซึ่งหมายความว่าฟังก์ชันสามารถรับStringอาร์กิวเมนต์ได้หลายอย่าง:

myMethod("foo", "bar");
myMethod("foo", "bar", "baz");
myMethod(new String[]{"foo", "var", "baz"}); // you can even pass an array

จากนั้นคุณสามารถใช้Stringvar เป็นอาร์เรย์:

public void myMethod(String... strings){
    for(String whatever : strings){
        // do what ever you want
    }

    // the code above is is equivalent to
    for( int i = 0; i < strings.length; i++){
        // classical for. In this case you use strings[i]
    }
}

คำตอบนี้ยืมมาอย่างหนักจาก kiswa's และ Lorenzo's ... และจากความคิดเห็นของ Graphain


13
เมื่อรหัสถึง bytecode มันเป็นอาร์เรย์ ทุกอย่างเป็นไวยากรณ์ที่ได้รับการสนับสนุนโดยคอมไพเลอร์
Donal Fellows

คำตอบนี้ยืมมาอย่างหนักจาก kiswa's และ Lorenzo ถ้าฉันอ่านการแก้ไขอย่างถูกต้อง
Matt Mitchell

3
@ กราฟ 'ดีกว่าที่จะแก้ไขคำตอบของคุณและทำให้ถูกต้องมากกว่าปล่อยไว้ตามลำพัง และถ้าคำตอบอื่นคือที่มาของการปรับปรุงของคุณมันจะไป อย่างน้อยเขาก็ซื่อสัตย์กับมัน (และฉันคิดว่าเขาตอบคำถามอื่น ๆ ที่ช่วยเขา ... ใช่ไหม?

1
@ เขาจะซื่อสัตย์หลังจากที่ฉันชี้ให้เห็นว่าดีพอ ขอบคุณที่มอง
Matt Mitchell

23

มันเป็น Varargs :)

varargs สั้นสำหรับอาร์กิวเมนต์ที่มีความยาวผันแปรคือคุณลักษณะที่อนุญาตให้วิธีการยอมรับจำนวนตัวแปรของอาร์กิวเมนต์ (ศูนย์หรือมากกว่า) ด้วย varargs มันกลายเป็นเรื่องง่ายที่จะสร้างวิธีการที่ต้องใช้จำนวนตัวแปรของการขัดแย้ง มีการเพิ่มคุณสมบัติของอากิวเมนต์ตัวแปรใน Java 5

ไวยากรณ์ของ varargs

vararg ถูกทำให้เป็นจริงโดยสามจุดไข่ปลา (สามจุด) หลังจากชนิดข้อมูลรูปแบบทั่วไปของมันคือ

return_type method_name(data_type ... variableName){
}  

ต้องการ varargs

ก่อน Java 5 ในกรณีที่มีความต้องการตัวแปรจำนวนอาร์กิวเมนต์มีสองวิธีในการจัดการมัน

หากจำนวนอาร์กิวเมนต์สูงสุดวิธีสามารถทำได้น้อยและเป็นที่รู้จักดังนั้นวิธีการสร้างเวอร์ชันที่มากเกินไปอาจถูกสร้างขึ้นได้ หากจำนวนอาร์กิวเมนต์สูงสุดที่วิธีสามารถทำได้นั้นมีขนาดใหญ่หรือ / และไม่ทราบวิธีการนั้นก็คือการใส่อาร์กิวเมนต์เหล่านั้นลงในอาร์เรย์และส่งผ่านไปยังวิธีที่รับอาร์เรย์เป็นพารามิเตอร์ วิธีการทั้งสองนี้มีข้อผิดพลาดเกิดขึ้นบ่อยครั้งการสร้างอาเรย์ของพารามิเตอร์ทุกครั้งและยากต่อการบำรุงรักษาเนื่องจากการเพิ่มอาร์กิวเมนต์ใหม่อาจส่งผลให้เกิดการเขียนวิธีโอเวอร์โหลดใหม่

ข้อดีของ varargs

เสนอตัวเลือกที่ง่ายกว่ามาก โค้ดน้อยลงโดยไม่จำเป็นต้องเขียนวิธีการโอเวอร์โหลด

ตัวอย่างของ varargs

public class VarargsExample {
 public void displayData(String ... values){
  System.out.println("Number of arguments passed " + values.length);
  for(String s : values){
   System.out.println(s + " ");
  }
 }

 public static void main(String[] args) {
  VarargsExample vObj = new VarargsExample();
  // four args
  vObj.displayData("var", "args", "are", "passed");
  //three args
  vObj.displayData("Three", "args", "passed");
  // no-arg
  vObj.displayData();
 }
}
Output

Number of arguments passed 4
var 
args 
are 
passed 
Number of arguments passed 3
Three 
args 
passed 
Number of arguments passed 0

มันสามารถเห็นได้จากโปรแกรมที่ใช้ความยาวที่นี่เพื่อหาจำนวนของข้อโต้แย้งที่ส่งผ่านไปยังวิธีการ เป็นไปได้เพราะ varargs ถูกส่งผ่านทางอ้อมเป็นอาร์เรย์ อาร์กิวเมนต์ใดก็ตามที่ถูกส่งผ่านเป็น varargs จะถูกเก็บไว้ในอาร์เรย์ซึ่งอ้างอิงโดยชื่อที่กำหนดให้กับ varargs ในชื่ออาร์เรย์โปรแกรมนี้เป็นค่า นอกจากนี้โปรดทราบว่าวิธีการนั้นถูกเรียกด้วยจำนวนอาร์กิวเมนต์ที่แตกต่างกันการเรียกครั้งแรกด้วยสี่อาร์กิวเมนต์จากนั้นสามอาร์กิวเมนต์และจากนั้นจะมีศูนย์อาร์กิวเมนต์ การเรียกทั้งหมดเหล่านี้ได้รับการจัดการโดยวิธีการเดียวกับที่ใช้เวลาเป็น

ข้อ จำกัด กับ varargs

เป็นไปได้ที่จะมีพารามิเตอร์อื่นที่มีพารามิเตอร์ varargs ในวิธีการอย่างไรก็ตามในกรณีนั้นพารามิเตอร์ varargs จะต้องเป็นพารามิเตอร์สุดท้ายที่ประกาศโดยวิธีการ

void displayValues(int a, int b, int  values) // OK
   void displayValues(int a, int b, int  values, int c) // compiler error

ข้อ จำกัด อื่นที่มี varargs คือต้องมีพารามิเตอร์ varargs เพียงพารามิเตอร์เดียวเท่านั้น

void displayValues(int a, int b, int  values, int  moreValues) // Compiler error

วิธีการมากเกินไป varargs

เป็นไปได้ที่จะโอเวอร์โหลดเมธอดที่รับพารามิเตอร์ varargs วิธีการ Varargs สามารถโอเวอร์โหลดโดย -

ประเภทของพารามิเตอร์ vararg สามารถแตกต่างกันได้ โดยการเพิ่มพารามิเตอร์อื่น ๆ ตัวอย่างของวิธีการบรรทุกเกินพิกัดวิธีการ

public class OverloadingVarargsExp {
 // Method which has string vararg parameter
 public void displayData(String ... values){
  System.out.println("Number of arguments passed " + values.length);
  for(String s : values){
   System.out.println(s + " ");
  }
 }

 // Method which has int vararg parameter
 public void displayData(int ... values){
  System.out.println("Number of arguments passed " + values.length);
  for(int i : values){
   System.out.println(i + " ");
  }
 }

 // Method with int vararg and one more string parameter
 public void displayData(String a, int ... values){
  System.out.println(" a " + a);
  System.out.println("Number of arguments passed " + values.length);
  for(int i : values){
   System.out.println(i + " ");
  }
 }

 public static void main(String[] args) {
  OverloadingVarargsExp vObj = new OverloadingVarargsExp();
  // four string args
  vObj.displayData("var", "args", "are", "passed");

  // two int args
  vObj.displayData(10, 20);

  // One String param and two int args
  vObj.displayData("Test", 20, 30);
 }
}
Output

Number of arguments passed 4
var 
args 
are 
passed 

Number of arguments passed 2
10 
20

 a Test
Number of arguments passed 2
20 
30 

ความหลากหลายและความคลุมเครือเกินพิกัด

ในบางกรณีการโทรอาจไม่ชัดเจนในขณะที่เรามีวิธี varargs มากเกินไป ลองดูตัวอย่าง

public class OverloadingVarargsExp {
 // Method which has string vararg parameter
 public void displayData(String ... values){
  System.out.println("Number of arguments passed " + values.length);
  for(String s : values){
   System.out.println(s + " ");
  }
 }

 // Method which has int vararg parameter
 public void displayData(int ... values){
  System.out.println("Number of arguments passed " + values.length);
  for(int i : values){
   System.out.println(i + " ");
  }
 }

 public static void main(String[] args) {
  OverloadingVarargsExp vObj = new OverloadingVarargsExp();
  // four string args
  vObj.displayData("var", "args", "are", "passed");

  // two int args
  vObj.displayData(10, 20);

  // This call is ambiguous
  vObj.displayData();
 }
}

ในโปรแกรมนี้เมื่อเราทำการเรียกเมธอด displayData () โดยไม่มีพารามิเตอร์ใด ๆ มันจะพ่นข้อผิดพลาดเนื่องจากคอมไพเลอร์ไม่แน่ใจว่าการเรียกเมธอดนี้ใช้สำหรับdisplayData(String ... values)หรือdisplayData(int ... values)

วิธีเดียวกันถ้าเรามีวิธีการมากเกินไปที่หนึ่งมีvarargวิธีหนึ่งประเภทและวิธีอื่นมีหนึ่งพารามิเตอร์และvarargพารามิเตอร์ประเภทเดียวกันแล้วเราก็มีความกำกวม - As Exp - displayData(int ... values)และdisplayData(int a, int ... values)

วิธีการโอเวอร์โหลดทั้งสองวิธีนี้มักจะมีความกำกวมอยู่เสมอ


15

นี่เป็นวิธี Java เพื่อส่งผ่านvarargs (อาร์กิวเมนต์หมายเลขตัวแปร)

หากคุณคุ้นเคยกับ C นี่จะคล้ายกับ...ไวยากรณ์ที่ใช้กับprintfฟังก์ชัน:

int printf(const char * format, ...);

แต่ในประเภทที่ปลอดภัยประเภท: ทุกอาร์กิวเมนต์จะต้องสอดคล้องกับประเภทที่ระบุ (ในตัวอย่างของคุณพวกเขาควรจะทั้งหมดString)

นี่เป็นตัวอย่างง่ายๆของวิธีที่คุณสามารถใช้varargs :

class VarargSample {

   public static void PrintMultipleStrings(String... strings) {
      for( String s : strings ) {
          System.out.println(s);
      }
   }

   public static void main(String[] args) {
      PrintMultipleStrings("Hello", "world");
   }
}

...อาร์กิวเมนต์เป็นจริงอาร์เรย์เพื่อให้คุณสามารถผ่านString[]เป็นพารามิเตอร์


11

มันเป็นตัวอย่างของน้ำตาล syntactic เพราะมันถูกนำมาใช้เป็นอาร์เรย์ anyways (ซึ่งไม่ได้หมายความว่ามันไร้ประโยชน์) - ฉันชอบที่จะผ่านอาร์เรย์เพื่อให้ชัดเจนและยังประกาศวิธีการที่มีอาร์เรย์ของประเภทที่กำหนด แต่ความเห็นมากกว่าคำตอบ


5

นอกจากนี้เพื่อลดแสงบางอย่างสิ่งสำคัญคือต้องรู้ว่าพารามิเตอร์ var-arg ถูก จำกัด ไว้ที่หนึ่งและคุณไม่สามารถมีพารามิเตอร์ var-art หลายรายการ เช่นนี้เป็นภาพลวงตา:

public void myMethod(String... strings, int ... ints){
// method body
}


2

วิธีที่ใช้กันทั่วไปเพื่อดูตัวอย่างที่ชัดเจนของการใช้จุดสามจุดที่มีอยู่ในหนึ่งในวิธีการที่โด่งดังที่สุดใน Android AsyncTask (วันนี้ไม่ได้ใช้มากเกินไปเนื่องจาก RXJAVA ไม่พูดถึงองค์ประกอบสถาปัตยกรรมของ Google) คุณสามารถค้นหาตัวอย่างมากมายที่ค้นหาคำศัพท์นี้และวิธีที่ดีที่สุดในการเข้าใจและไม่ลืมอีกต่อไปความหมายของสามจุดคือพวกเขาแสดง ... สงสัย ... เหมือนในภาษาทั่วไป กล่าวคือยังไม่ชัดเจนว่าจำนวนพารามิเตอร์ที่ต้องผ่านอาจเป็น 0 อาจเป็น 1 อาจจะมากกว่า (อาร์เรย์) ...


1

String... เป็นเช่นเดียวกับ String[]

import java.lang.*;

public class MyClassTest {

    //public static void main(String... args) { 

    public static void main(String[] args) {
        for(String str: args) {
            System.out.println(str);
        }
    }
}

1
หากString...เป็นเช่นเดียวกับString[]คุณไม่สามารถพูดได้ใช่ไหม
Scott Hunter

8
เทคนิคไม่เป็นความจริงเพราะString[]ต้องมีอาร์กิวเมนต์ (อย่างน้อยอาร์เรย์ว่าง) ในขณะที่String...ไม่ได้ (ดูคำตอบข้างต้น)
Aurel

0

การเพิ่มไปยังคำตอบที่เขียนอย่างดีอื่น ๆ ข้อได้เปรียบของvaragrsฉันพบว่ามีประโยชน์คือเมื่อฉันเรียกวิธีการที่มีอาร์เรย์เป็นชนิดพารามิเตอร์จะใช้ความเจ็บปวดจากการสร้างอาร์เรย์; เพิ่มองค์ประกอบแล้วส่ง แต่ฉันสามารถเรียกวิธีที่มีค่ามากที่สุดเท่าที่ฉันต้องการ จากศูนย์ถึงมาก


0
  • มันหมายถึงพารามิเตอร์ศูนย์หรือหลายพารามิเตอร์ของชนิดข้อมูลเดียวกัน
  • มันจะต้องเป็นพารามิเตอร์สุดท้ายของตัวสร้างหรือฟังก์ชั่น
  • เราสามารถมีพารามิเตอร์ประเภทนี้เพียงตัวเดียวในคอนสตรัคเตอร์หรือฟังก์ชั่นที่เกี่ยวข้อง

ตัวอย่างที่ 1:

public class quest1 {

    public quest1(String... mynum) {
        System.out.println("yee haa");
    }

    public static void main(String[] args) {
        quest1 q=new quest1();

        quest1 q1=new quest1("hello");

    }
}

ตัวอย่างที่ 2:

public class quest1 {

    public quest1(int... at) {
        System.out.println("yee haa");
    }

    public quest1(String... at) {
        System.out.println("yee haa");
    }

    public static void main(String[] args) {
        quest1 q=new quest1("value");

        quest1 q1=new quest1(1);

    }

    public void name(String ... s) {

    }
}

เอาท์พุท:

ใช่แล้ว

ใช่แล้ว


-1

ไวยากรณ์: (จุดสามจุด ... ) -> หมายถึงเราสามารถเพิ่มวัตถุเป็นศูนย์หรือมากกว่าผ่านในการขัดแย้งหรือผ่านอาร์เรย์ประเภทวัตถุ

public static void main(String[] args){}
public static void main(String... args){}

คำจำกัดความ: 1) อาร์กิวเมนต์ Object ... เป็นเพียงการอ้างอิงไปยังอาร์เรย์ของวัตถุ

2) ('String []' หรือ String ... ) สามารถจัดการวัตถุสตริงจำนวนเท่าใดก็ได้ ภายในจะใช้อาร์เรย์ของวัตถุประเภทอ้างอิง

i.e. Suppose we pass an Object array to the ... argument - will the resultant argument value be a two-dimensional array - because an Object[] is itself an Object:

3) ถ้าคุณต้องการเรียกใช้เมธอดที่มีอากิวเมนต์เดียวและมันเกิดขึ้นเป็นอาเรย์คุณจะต้องล้อมมันด้วย

another. method(new Object[]{array}); 
OR 
method((Object)array), which will auto-wrap.

แอปพลิเคชัน: ส่วนใหญ่จะใช้เมื่อจำนวนอาร์กิวเมนต์เป็นแบบไดนามิก (จำนวนอาร์กิวเมนต์ที่ทราบที่รันไทม์) และในการแทนที่ กฎทั่วไป - ในวิธีการที่เราสามารถผ่านประเภทใด ๆ และจำนวนข้อโต้แย้งใด ๆ เราไม่สามารถเพิ่มอาร์กิวเมนต์ object (... ) ก่อนอาร์กิวเมนต์ใด ๆ กล่าวคือ

void m1(String ..., String s) this is a wrong approach give syntax error.
void m1(String s, String ...); This is a right approach. Must always give last order prefernces.   
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.