可変長引数の制約とオーバーロード優先順位
最後の引数にしか置けません。通常のオーバーロードが優先される順序も解説します。
エラーメッセージの読み方
Main.java:8: error: method sum in class Main cannot be applied to given types;
Main.java- ファイル名
8- 行番号 — javacが異常に気づいた位置。原因の行とは限りません
error- 種別 — コンパイルエラー。実行まで到達しません
method sum in class Main cannot be applied to given types;- 内容 — javacが期待していたもの、または見つけられなかったもの
このエラーが出る典型パターン
パターン1
1 public class Main { 2 static int sum(int[] nums) { ^ 3 int t = 0; 4 for (int n : nums) t += n; 5 return t; 6 } 7 public static void main(String[] args) { 8 System.out.println(sum(1, 2, 3)); 9 } 10 }
Main.java:8: error: method sum in class Main cannot be applied to given types;
required: int[] found: int,int,int
可変長引数は型の後に ... を書きます。呼び出し側はカンマ区切りでも配列でも渡せます。
直し方: [] を ... にします。
広告
広告スロット(未設定)
パターン2
1 public class Main { 2 static void log(String tag, int... nums, String args) { ^ 3 System.out.println(tag + args.length); 4 } 5 public static void main(String[] args) { 6 log("x", 1, 2); 7 } 8 }
Main.java:2: error: varargs parameter must be the last parameter
可変長引数は必ず最後の引数にします。複数置くこともできません。
直し方: int... nums, String を Object... にします。
パターン3
1 public class Main { 2 static void f(Object... a) { System.out.println("varargs"); } 3 static void f(Object a) { System.out.println("single"); } 4 public static void main(String[] args) { 5 f("x" ); ^ 6 } 7 }
出力: single(引数1つのときは可変長より通常のオーバーロードが優先されます)
可変長引数は最後の候補として選ばれます。曖昧さを避けるため、同名で両方定義しないのが安全です。
直し方: "x" を "x" にします。
パターン4
1 public class Main { 2 static void f(int... nums) { System.out.println("ints"); } 3 static void f(String... strs) { System.out.println("strings"); } 4 public static void main(String[] args) { 5 f( ); ^ 6 } 7 }
Main.java:5: error: reference to f is ambiguous
引数なしの呼び出しは、どちらの可変長引数も長さ0で受け取れるためあいまいです。型が決まる引数を1つ渡すと解決します。
直し方: (空) を 1 にします。
パターン5
1 public class Main { 2 static void f(Object... items) { System.out.println(items.length); } 3 public static void main(String[] args) { 4 int[] nums = {1, 2, 3}; 5 f(nums ); ^ 6 } 7 }
出力: 1期待: 3 (コンパイルは通っています)
int[]はObject[]ではないため、可変長引数に渡すと配列全体が1個のオブジェクトとして扱われます。個々の値を渡すには要素を並べます。
直し方: nums を 1, 2, 3 にします。
よくある誤解
引数ゼロでも呼び出せます。渡されなかった場合はnullではなく長さ0の配列になるので、nullチェックではなくlengthを見ます。
実務での勘所
可変長引数とオーバーロードが両方候補になる場面で、Javaは3段階の優先順位で解決します。まずボクシングや可変長引数を使わずに一致するメソッドを探し、次にオートボクシングを使えば一致するメソッドを探し、それでも決まらない場合に最後の手段として可変長引数のメソッドを使います。print(int a, int b)とprint(int... nums)の両方がある状態でprint(1, 2)と呼ぶと、可変長引数の方ではなく必ず固定引数の方が選ばれます。「可変長引数の方が汎用的だから優先されそう」という直感は逆です。