JDK 5 引入,允許方法接受**同類型、不定數量**參數,本質是**語法糖**,編譯器自動封裝為陣列。
// 定義:類型... 參數名
public static void print(String... args) {
for (String s : args) System.out.println(s);
}
// 調用方式多樣
print(); // 空陣列
print("A"); // 單元素
print("A", "B", "C"); // 多元素
print(new String[]{"X","Y"}); // 陣列直接傳遞
// 源碼
print("A", "B", "C");
// 編譯後等價於
print(new String[]{"A", "B", "C"});
// 位元組碼
INVOKESTATIC Print.print ([Ljava/lang/String;)V
| 規則 | 說明 | 示例 |
|---|---|---|
| 同類型 | 所有可變參數必須相同類型 | void m(int... a) ✓ / void m(int... a, String... b) ✗ |
| 最後一個參數 | 可變參數**必須**是最後一個形參 | void m(int x, String... args) ✓ / void m(String... args, int x) ✗ |
| 最多一個 | 每個方法只能有一個可變參數 | void m(int... a, int... b) ✗ |
| 可為空 | 調用時可傳 0 個參數,方法內接收空陣列 | m() → args.length == 0 |
| 重載優先級 | 固定參數優於可變參數匹配 | 見下文陷阱 |
public class VarargsOverload {
static void m(int x) { System.out.println("fixed: " + x); }
static void m(int... xs) { System.out.println("varargs: " + xs.length); }
public static void main(String[] args) {
m(1); // fixed: 1 (精確匹配優先)
m(1, 2); // varargs: 2
m(); // varargs: 0
m(new int[]{}); // varargs: 0
}
}
public void log(String format, Object... args) {
System.out.printf(format + "%n", args);
}
// log("User: %s, Age: %d", "Alice", 25);
public static List asList(T... elements) {
return Arrays.asList(elements); // 固定長度列表
}
// List list = asList("A", "B", "C");
// 當參數類型不同時,用 Builder 模式
public class Request {
private String url;
private Map headers;
private String body;
public static Builder builder() { return new Builder(); }
public static class Builder {
// 鏈式設置...
public Request build() { return new Request(this); }
}
}
void m(int a) void m(int a, int b) 避免陣列分配Arrays.asList 返回固定長度列表,**不可增刪**,需 `new ArrayList<>(asList(...))`
// 陣列 -> List
List list = Arrays.asList("A", "B", "C"); // 固定長度
List mutable = new ArrayList<>(Arrays.asList("A", "B"));
// List -> 陣列
String[] arr = list.toArray(new String[0]); // JDK 11+ 推薦 new String[0]
// Stream 互轉
Stream.of("A", "B").toArray(String[]::new);
Arrays.stream(arr).collect(Collectors.toList());
| 錯誤代碼 | 問題 | 修正 |
|---|---|---|
void m(String... a, String... b) | 多個可變參數 | 合併為一個或用集合 |
void m(String... args, int x) | 可變參數非最後 | 調整順序 |
if (args == null) | 永遠不為 null(空陣列) | if (args.length == 0) |
| 修改 args 影響調用者 | 陣列引用傳遞 | 防禦性複製 args = args.clone() |
| 重載模糊調用 | m(1) 匹配固定/可變均可 | 避免同類型重載,或用不同方法名 |
String.format(String, Object...)Arrays.asList(T...)Collections.addAll(Collection, T...)ExecutorService.submit(Runnable...)ProcessBuilder(String...)EnumSet.of(E, E...)可變參數是**簡化 API、提升可讀性**的語法糖,本質是陣列。掌握重載優先級、空陣列語義、性能影響,配合 Builder 模式處理複雜參數,是設計優雅 Java API 的關鍵技能。