私は質問があります:これらの2つの宣言の違いは何ですか?
public static void printMax(double... numbers) { ... }
public static void printmax(double numbers[]) { ... }
double... numbers
と同じですかdouble numbers[]
?
私は質問があります:これらの2つの宣言の違いは何ですか?
public static void printMax(double... numbers) { ... }
public static void printmax(double numbers[]) { ... }
double... numbers
と同じですかdouble numbers[]
?
メソッドパラメータ宣言のType...
構成は、一般にvarargsと呼ばれるものです。JLSでは、これは可変アリティパラメータと呼ばれます。
リストの最後の正式なパラメータは特別です。タイプに続く省略記号で示される、可変のアリティパラメータである可能性があります。
最後の仮パラメータが型の可変アリティパラメータである場合、型
T
の仮パラメータを定義すると見なされますT[]
。その場合、このメソッドは可変アリティメソッドになります。それ以外の場合は、固定アリティ方式です。可変アリティメソッドの呼び出しには、仮パラメーターよりも実際の引数式が多く含まれる場合があります。変数arityパラメーターの前にある仮パラメーターに対応しないすべての実際の引数式が評価され、結果が配列に格納されて、メソッド呼び出しに渡されます。
コードで説明するために、これはvarargsで実行できることです。
static void f(int... nums) {
for (int num : nums) {
System.out.println(num);
}
}
//...
f(1,2,3); // prints "1", "2", "3"
対照的に、varargs構文がない場合は、次のことを行う必要があります。
static void g(int[] nums) {
for (int num : nums) {
System.out.println(num);
}
}
//...
g(new int[] { 1, 2, 3 }); // prints "1", "2", "3"
varargsは、冗長性をあなたから隠す、いわゆるシンタックスシュガーです。
質問に戻ると、との違いprintMax(double... numbers)
はprintmax(double numbers[])
、最初のメソッドは可変アリティメソッドであるということです。つまり、可変数のパラメーターを指定できます。後者は固定アリティメソッドであり、唯一のパラメータを受け入れることを意味します。
T...
本当にであることについての上記の引用に注意してくださいT[]
。つまり、varargsを使用しても、次のことができます。
f(new int[] { 1, 2, 3 }); // prints "1", "2", "3"
ここでは、varargパラメーターを保持する配列を手動で作成しています。f
実際、コードを逆コンパイルするところまで行くと、JLSが指定したように、実際にはint[]
パラメーターを取り、f(1, 2, 3)
として実装されていることがわかりますf(new int[] { 1, 2, 3 })
。
varargsがどのように解決されるかは非常に複雑であり、時にはそれはあなたを驚かせるかもしれないことをします。
この例を考えてみましょう。
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
しobjs.length
ます。varargsパラメーターに1つnull
の引数を指定する場合は、次のいずれかを実行できます。
count(new Object[] { null }); // prints "1"
count((Object) null); // prints "1"
以下は、varargsを扱うときに人々が尋ねたいくつかの質問のサンプルです。
前のセクションで示したように、varargsは注意が必要です。ただし、適切な状況で使用すると、はるかに簡潔なコードにつながる可能性があります。
これは、Effective Java 2nd Edition、Item 42からの引用です:varargsを慎重に使用してください(作成者による強調):
教訓は明らかです。最終的な配列パラメーターを持つすべてのメソッドを後付けしないでください。varargsは、呼び出しが実際に可変長の値のシーケンスで動作する場合にのみ使用してください。
varargsは混乱を招くだけでなく、コストもかかる可能性があります。効果的なJava2ndEditionは、実際には、最も一般的な使用シナリオに対して固定アリティのオーバーロードを提供することを推奨しています。
メソッドの呼び出しの95%に3つ以下のパラメーターがあると判断したとします。次に、メソッドの5つのオーバーロードを宣言します。1つは0から3つの通常のパラメーターで、パラメーターの数が3を超える場合に使用する単一のvarargsです。
この本はさらに深く掘り下げられていますが、基本的には、実際に意味がある場合にのみvarargsを使用する必要があります。また、そのような場合でも、パフォーマンス上の理由から、固定アリティのオーバーロードを提供することを検討することをお勧めします。
varargsが理にかなっているいくつかの例を次に示します。
java.util.Arrays.asList(T...)
java.util.PrintStream.printf(String format, Object... args)
java.lang.reflect.Method.invoke(Object obj, Object... args)
次のように配列を宣言する習慣をつけないでください。
int x[];
代わりに、識別子ではなく、タイプで角かっこを配置する必要があります。
int[] x;
これは、上記の説明で配列が参照される方法でもあることに注意してくださいT[]
int[]
。
Object[] x
ありObject x[]
ますか?int[] myArray
との違いint myArray[]
int[] k,i
とint k[],i
i
!の型が異なります。printMax
主な違いは、最初のケースでは、複数の引数を使用して呼び出すことができることです。
printMax(3.0, 4.0, 5.0)
一方、2番目のケースでは、単一の引数(の配列)のみを受け入れdouble
ます。
メソッド本体内では、どちらの場合も数値は配列としてアクセスされます。
覚えておくべきことの1つは、最初のケースではdouble
、varargs表記が使用されていても、の単一の配列を渡すことができるということです。
正確には-double...は可変引数リストを意味します-この時点で渡されるすべての引数は1つの配列として一緒にパックされます。
メソッドにはvarargパラメーターが1つしか存在できず、明らかな理由から、プロトタイプの最後である必要があります。ただし、メソッドでは配列として使用できるため、この特定のケースでは大きな違いはありません。