web-dev-qa-db-ja.com

Java varargs method param list vs. array

可変引数:

public static void foo(String... string_array) { ... }

versus

単一配列パラメーター:

public static void bar(String[] string_array) { ... }

Java 1.6は、以下を受け入れる/拒否するようです。

String[] arr = {"abc", "def", "ghi"};
foo(arr);  // accept
bar(arr);  // accept
foo("abc", "def", "ghi");  // accept
bar("abc", "def", "ghi");  // reject

上記が正しい/正しいと仮定して、なぜ単一の配列パラメーターの代わりに常に可変引数を使用しないのですか?無料で発信者の柔軟性のタッチを追加するようです。

専門家は内部JVMの違いを共有できますか?

ありがとう。

35
kevinarpe

配列はJavaの初期から存在していましたが、可変引数はごく最近の追加です。そのため、多くの古いコードは依然として配列を使用しています。

また、明示的な配列パラメーターを使用して汎用varargメソッドを呼び出すと、予想とは異なる動作がサイレントに生成される場合があることに注意してください。

_public <T> void foo(T... params) { ... }

int[] arr = {1, 2, 3};

foo(arr); // passes an int[][] array containing a single int[] element
_

したがって、明確な利点を得るために多大な努力を必要とすることを除けば、レガシー配列パラメーターを可変引数に置き換えることは必ずしも望ましいとは限りません。

メソッドパラメータリストの配列の後に別のパラメータがあるため、できない場合は言うまでもありません。

_public void foo(String[] strings, String anotherParam) { ... }
_

パラメータを並べ替えることで技術的に解決できる場合がありますが、クライアントコードが破損します。

更新:有効Java 2nd。Edition、Item 42:可変引数を慎重に使用するがこれを説明するより具体的には、具体的な例を示します:Arrays.asList()はvarargパラメーターを持つようにJava5で改良されました。 誤って多くの既存のコードを壊した この(現在では廃止された)イディオムを使用して配列を出力すると、驚きが生じる場合があります。

_System.out.println(Arrays.asList(myArray));
_

pdate2:ソースを再確認したところ、_int[]_などのプリミティブ型の配列で問題が発生したことがわかりました。可変引数の前に、このようなコード:

_int[] digits = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 4 };
System.out.println(Arrays.asList(digits));
_

参照型の配列しかListに変換できないため、コンパイルエラーが発生します。可変引数であり、asListを後付けするため、上記のコードは警告なしでコンパイルされ、意図しない結果は_"[[I@3e25a5]"_のようなものになります。

36
Péter Török

すべてを可変引数として指定しない主な理由は、常に意味をなさないことです。たとえば、 InputStream.read(byte[]) が `read(byte ...)として定義されている場合、次の呼び出しが有効になります。

myInputStream.read(0, 1, 2, 3);

これにより、4要素のバイト配列が作成され、渡されてから破棄されます。

8
Joachim Sauer

可変引数は、配列の単純な構文糖です。

foo("abc", "def", "ghi");を呼び出すと、コンパイラはfoo(new String[] {"abc", "def", "ghi"});として呼び出します

コンパイラは1つの新しい配列を作成し、foo()に渡します。 foo(String...)foo(String[])の両方を持つことはできません。両方が機能的に同じなので。

5

fooでは、3つのパラメーターを指定します。次のようにbarを呼び出す必要があります。

 bar(new String[]{"abc", "def", "ghi"});

したがって、1つのパラメータ、つまりこの場合は内部とはほとんど関係のないString []で呼び出すだけです。すべて文字列です

2
sharpner

これが、可変引数の定義方法です。 varargs拡張は、配列を受け入れるすべての配列をvarargs関数にするわけではありません。次のようにbarを呼び出す必要があります。

bar(new String[]{"abc", "def", "ghi"})
2
Daniel

もう1つの違いは効率です。明示的な配列内にあるオブジェクトは呼び出されません。ただし、変数引数リストのパラメーターは、メソッドがスタックにプッシュされるときに評価されます。

これは、関数呼び出しが、変数引数リストで使用されている型を返すパラメーターとして渡されたときに明らかです。

例:someMethod(Object ... x)anotherMethod(Object []);

someMethod(a()、b()、c()); //メソッドに入る前に、a、b、cが呼び出されます。

anotherMethod(new Object [] {a()、b()、c()}); //オブジェクトにアクセスするまでメソッドは呼び出されません。

1
Ken T.