次のような関数を作成したいと思います:
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)
? その場合は、新しい配列を使用してextraVar
を先頭に追加し、そのメソッドに渡すことができます。args
ベストアンサー1
はい、 a はT...
a の単なる構文糖衣です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[]
。また、配列は共変なので、 は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!!!
varargs が解決される方法により、最後のステートメントは を呼び出しobjs = null
、当然 が発生しますNullPointerException
。varargsパラメータにobjs.length
1 つの引数を与える場合はnull
、次のいずれかを実行できます。
count(new Object[] { null }); // prints "1"
count((Object) null); // prints "1"
関連する質問
以下は、可変引数を扱う際に人々が尋ねる質問の一部です。
可変引数の落とし穴 #2: 余分な引数を追加する
ご存知のとおり、以下は「機能しません」。
String[] myArgs = { "A", "B", "C" };
System.out.println(ezFormat(myArgs, "Z"));
// prints "[ [Ljava.lang.String;@13c5982 ][ Z ]"
varargs の動作方法により、ezFormat
実際には 2 つの引数を取得します。最初の引数はString[]
、2 番目の引数は です。varargs に配列を渡し、その要素を個別の引数として認識させ、さらに引数を追加する必要がある場合は、追加の要素を収容する別の配列String
を作成するしかありません。
以下に、便利なヘルパー メソッドをいくつか示します。
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 ]"
可変引数の落とし穴 #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 ]"