Javaで可変引数を持つメソッドに引数として配列を渡すことはできますか?


275

次のような関数を作成できるようにしたいと思います。

class A {
  private String extraVar;
  public String myFormat(String format, Object ... args){
    return String.format(format, extraVar, args);
  }
}

ここでの問題は、それがあるargsとして扱われるObject[]方法でmyFormat、ひいてはへの単一の引数であるString.format私はすべての単一たい一方で、Object中にはargs新しい引数として渡されます。String.formatも可変引数を持つメソッドなので、これは可能であるべきです。

これが不可能な場合、次のような方法はありString.format(String format, Object[] args)ますか?その場合、私は新しい配列extraVarargs使用することに付加して、それをそのメソッドに渡すことができます。


8
どうしてこの質問が「これは有効なのか」という質問なのか疑問に思わずにはいられません。試してみませんか?無理をしないでください、あなたは自分より良い害を及ぼすでしょう。
kamasheto 2010年

21
十分に本当ですが、これは簡単にテストできたでしょう。ただし、このような質問の良い点は、トピックを公開し、興味深い回答を求めることです。
akf

2
メソッドの引数として配列argsを渡すつもりで、実際に上記のコードを試しました。しかし、argsの前にextraVarを追加する必要があることを理解していませんでした。変数の引数が配列として扱われることがわかっている場合(メソッドの外でも)、これはもちろん非常に論理的です。
user362382 2010年

回答:


180

可変個引数メソッドの基礎となる型function(Object... args) function(Object[] args)です。Sunは、後方互換性を維持するために、この方法で可変引数を追加しました。

したがって、先頭extraVarにを付けてargs呼び出すことができるはずですString.format(format, args)


型の引数を渡すX[]方法には、x(X... xs)Eclipseで次の警告を与える:Type X[] of the last argument to method x(X...) doesn't exactly match the vararg parameter type. Cast to X[] to confirm the non-varargs invocation, or pass individual arguments of type X for a varargs invocation.
ルークハチソン

318

はい、a T...はの構文糖にすぎませんT[]

JLS 8.4.1フォーマットのパラメーター

リストの最後の仮パラメーターは特別です。タイプに続く省略記号で示される可変アリティパラメータである場合があります

最後の仮パラメータがタイプの可変アリティパラメータである場合T、それはタイプの仮パラメータを定義すると見なされますT[]。このメソッドは可変アリティメソッドです。それ以外の場合は、固定アリティメソッドです。可変アリティメソッドの呼び出しには、仮パラメーターよりも実際の引数式が含まれる場合があります。可変引数パラメーターの前にある仮パラメーターに対応しないすべての実際の引数式が評価され、結果が配列に格納され、メソッド呼び出しに渡されます。

以下に例を示します。

public static String ezFormat(Object... args) {
    String format = new String(new char[args.length])
        .replace("\0", "[ %s ]");
    return String.format(format, args);
}
public static void main(String... args) {
    System.out.println(ezFormat("A", "B", "C"));
    // prints "[ A ][ B ][ C ]"
}

そして、はい、上記main再び、ための方法は、有効であるString...だけですString[]。また、配列は共変であるため、a String[]Object[]なので、ezFormat(args)どちらの方法でも呼び出すことができます。

こちらもご覧ください


Varargsの落とし穴#1:合格 null

可変引数がどのように解決されるかは非常に複雑であり、時には驚かれることがあります。

この例を考えてみましょう:

static void count(Object... objs) {
    System.out.println(objs.length);
}

count(null, null, null); // prints "3"
count(null, null); // prints "2"
count(null); // throws java.lang.NullPointerException!!!

可変引数がどのように解決されるかにより、最後のステートメントはで呼び出されますがobjs = null、これはもちろんで引き起こさNullPointerExceptionobjs.lengthます。nullvarargsパラメータに1つの引数を指定する場合は、次のいずれかを実行できます。

count(new Object[] { null }); // prints "1"
count((Object) null); // prints "1"

関連する質問

以下は、可変引数を扱うときに人々が尋ねたいくつかの質問のサンプルです。


Varargの落とし穴#2:追加の引数を追加する

ご存知のように、以下は機能しません。

    String[] myArgs = { "A", "B", "C" };
    System.out.println(ezFormat(myArgs, "Z"));
    // prints "[ [Ljava.lang.String;@13c5982 ][ Z ]"

varargsの動作方法により、ezFormat実際には2つの引数を取得します。最初の引数String[]は、2番目の引数はStringです。配列をvarargsに渡し、その要素を個別の引数として認識させたい場合、さらに引数を追加する必要がある場合は、追加の要素に対応する別の配列を作成するしかありません。

いくつかの便利なヘルパーメソッドを次に示します。

static <T> T[] append(T[] arr, T lastElement) {
    final int N = arr.length;
    arr = java.util.Arrays.copyOf(arr, N+1);
    arr[N] = lastElement;
    return arr;
}
static <T> T[] prepend(T[] arr, T firstElement) {
    final int N = arr.length;
    arr = java.util.Arrays.copyOf(arr, N+1);
    System.arraycopy(arr, 0, arr, 1, N);
    arr[0] = firstElement;
    return arr;
}

これで、次のことができます。

    String[] myArgs = { "A", "B", "C" };
    System.out.println(ezFormat(append(myArgs, "Z")));
    // prints "[ A ][ B ][ C ][ Z ]"

    System.out.println(ezFormat(prepend(myArgs, "Z")));
    // prints "[ Z ][ A ][ B ][ C ]"

Varargsの落とし穴#3:プリミティブの配列を渡す

「動かない」:

    int[] myNumbers = { 1, 2, 3 };
    System.out.println(ezFormat(myNumbers));
    // prints "[ [I@13c5982 ]"

Varargsは参照型でのみ機能します。オートボクシングはプリミティブの配列には適用されません。次の作品:

    Integer[] myNumbers = { 1, 2, 3 };
    System.out.println(ezFormat(myNumbers));
    // prints "[ 1 ][ 2 ][ 3 ]"

2
Object ...可変パラメータを使用すると、プリミティブ引数でさえオブジェクトにオートボックス化できるシグネチャ間のあいまいさをコンパイラが識別するため、追加のシグネチャを使用することが難しくなります。
eel ghEEz 2015

7
getchaがありません:メソッドにObjectタイプの最後のパラメーターがあり、たとえばString []を渡して呼び出す場合。コンパイラーは、配列が可変引数の最初の項目であるか、すべての可変引数の同等物であるかを認識していません。それはあなたに警告します。
Snicolas

型の引数を渡すX[]方法には、x(X... xs)Eclipseで次の警告を与える:Type X[] of the last argument to method x(X...) doesn't exactly match the vararg parameter type. Cast to X[] to confirm the non-varargs invocation, or pass individual arguments of type X for a varargs invocation.
ルークハチソン

23

配列を渡すことは問題ありません-実際には同じことになります

String.format("%s %s", "hello", "world!");

と同じです

String.format("%s %s", new Object[] { "hello", "world!"});

これは単なる構文上の糖衣です。基本となるメソッドはvarargパラメータの配列を想定しているため、コンパイラは最初のものを2番目のものに変換します。

見る


4

jasonmp85は、別の配列をに渡すのに適していString.formatます。配列のサイズは一度作成すると変更できないため、既存の配列を変更するのではなく、新しい配列を渡す必要があります。

Object newArgs = new Object[args.length+1];
System.arraycopy(args, 0, newArgs, 1, args.length);
newArgs[0] = extraVar; 
String.format(format, extraVar, args);

1

私は同じ問題を抱えていました。

String[] arr= new String[] { "A", "B", "C" };
Object obj = arr;

次に、objをvarargs引数として渡しました。出来た。


2
それも追加してください。
Mathews Sunny、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.