[Java]可変長引数とオーバーロード その2

2016年10月3日月曜日

Java

可変長引数とオーバーロード その1ではEnumSetのofメソッドに可変長引数と引数1〜5個までのオーバーロードがあるのを見た。

もう一つ、可変長引数で注意しなければいけないのは以下のようなケースだ。
java.io.PrintStream::printfメソッドのようにさまざまな型を受け付ける可変長引数の場合を考えてみよう。

PrintStream printf(String format, Object ... args)

Javaの可変長引数の実体は配列であり、実際に配列を渡すこともできる。
なので、以下2例は同じ結果となる。
    System.out.printf("%s %s %s%n", "1", "2", "3");
    System.out.printf("%s %s %s%n", new String[]{ "1", "2", "3" });
1 2 3
1 2 3


これをStringの配列ではなく、intの配列にしてみよう。
    System.out.printf("%d %d %d%n", 1, 2, 3);
    System.out.printf("%d %d %d%n", new int[]{ 1, 2, 3 });
1 2 3
Exception in thread "main" java.util.IllegalFormatConversionException: d != [I
 at java.util.Formatter$FormatSpecifier.failConversion(Formatter.java:4302)
 at java.util.Formatter$FormatSpecifier.printInteger(Formatter.java:2793)
 at java.util.Formatter$FormatSpecifier.print(Formatter.java:2747)
 at java.util.Formatter.format(Formatter.java:2520)
 at java.io.PrintStream.format(PrintStream.java:970)
 at java.io.PrintStream.printf(PrintStream.java:871)
 at local.PrintfSample.main(PrintfSample.java:9)

2つ目のprintf呼び出しで例外発生。。。

どうして、こんなことになってしまうんだろう。
Javaの配列は共変なので、Object配列を期待している箇所であれば、Objectのサブクラスの配列を渡すことができる。 だから、printfのargs引数にStringの配列を渡しても問題はない。

ところが、intはObjectのサブクラスではないため、int[]という配列型の扱いになって、可変長引数の最初の項に吸収されてしまう。
このため、"%d"で配列は解釈できないってことになってしまったんだね。