以下のような関数を作成できるようにしたいです。
class A {
private String extraVar;
public String myFormat(String format, Object ... args){
return String.format(format, extraVar, args);
}
}
ここでの問題は、メソッドargs
ではmyFormat
がObject[]
として扱われるため、Object
内のすべてのargs
が新しい引数として渡されるようにしたいのですが、String.format
への単一の引数であることです。 String.format
も可変引数を持つメソッドなので、これは可能なはずです。
これが不可能な場合、String.format(String format, Object[] args)
のような方法はありますか?その場合は、新しい配列を使用してextraVar
をargs
の前に追加し、それをそのメソッドに渡すことができます。
可変個メソッドの基礎となる型function(Object... args)
isfunction(Object[] args)
。 Sunは、下位互換性を保つために、この方法で可変引数を追加しました。
ですから、extraVar
をargs
の前に追加してString.format(format, args)
を呼び出すことができるはずです。
はい、T...
はT[]
の単なる構文上の糖です。
リストの最後の仮パラメータは特別です。それは可変アリティパラメータであり、型に続く省略記号で示されます。
最後の仮パラメータが
T
型の可変アリティパラメータである場合、それは型T[]
の仮パラメータを定義すると見なされます。その場合の方法は可変アリティ方法です。それ以外の場合は、固定アリティメソッドです。可変アリティメソッドの呼び出しは、仮パラメータよりも実際の引数式を多く含むことがあります。変数arityパラメータの前の仮パラメータに対応しないすべての実引数式が評価され、結果がメソッド呼び出しに渡される配列に格納されます。
これは説明のための例です。
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)
を呼び出すことができます。
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
で呼び出します。もちろん、これはobjs.length
でNullPointerException
を引き起こします。 varargsパラメータに1つのnull
引数を与えたい場合は、次のいずれかを実行できます。
count(new Object[] { null }); // prints "1"
count((Object) null); // prints "1"
以下は、可変引数を扱う際に人々が尋ねたいくつかの質問の例です。
ご存知のとおり、次のものは「機能しません」。
String[] myArgs = { "A", "B", "C" };
System.out.println(ezFormat(myArgs, "Z"));
// prints "[ [Ljava.lang.String;@13c5982 ][ Z ]"
可変引数の機能上の理由から、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 ]"
それは "動作"しません:
int[] myNumbers = { 1, 2, 3 };
System.out.println(ezFormat(myNumbers));
// prints "[ [I@13c5982 ]"
可変引数は参照型でのみ機能します。オートボクシングは、プリミティブの配列には適用されません。次のように動作します。
Integer[] myNumbers = { 1, 2, 3 };
System.out.println(ezFormat(myNumbers));
// prints "[ 1 ][ 2 ][ 3 ]"
配列を渡しても構いません - 実際、同じものになります。
String.format("%s %s", "hello", "world!");
と同じです
String.format("%s %s", new Object[] { "hello", "world!"});
基本的なメソッドが vararg パラメータの配列を期待しているため、コンパイラは最初の構文を2番目の構文に変換します。
見る
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);
私は同じ問題を抱えていました。
String[] arr= new String[] { "A", "B", "C" };
Object obj = arr;
そして、objをvarargs引数として渡しました。出来た。