I have this simple varargs method which divides each item in the list:
import java.util.*;
class A {
static long f(long... xs) {
Arrays.sort(xs);
long y = 100000000;
for (int i = xs.length - 1; i >= 0; i--)
y /= xs[i];
return y;
}
static {
System.out.println(f(5,2,6,3,9,3,13,4,5));
long[] xs = new long[]{5,2,6,3,9,3,13,4,5};
System.out.println(Arrays.toString(xs));
System.out.println(f(xs));
System.out.println(Arrays.toString(xs));
}
}
I'd expect it to pass a copy of the array, but apparently it's somehow modifying the array I pass in, instead of its own local copy:
$ javac A.java && java A
79
[5, 2, 6, 3, 9, 3, 13, 4, 5]
79
[2, 3, 3, 4, 5, 5, 6, 9, 13]
So I wrote this simple test program:
class B {
static void f(Object... os) {
System.out.println(os);
}
static {
Object os = new Object[]{1,2,3};
System.out.println(os);
f(os);
}
}
And it does what I expect, it clones the object array before passing it into f
(hence different object identifiers):
$ javac B.java && java B
[Ljava.lang.Object;@1242719c
[Ljava.lang.Object;@4830c221
So how then is f
in A
modifying the caller's array instead of its own copy?
A method that takes a variable number of arguments is a varargs method. Prior to JDK 5, variable-length arguments could be handled two ways. One using overloaded method (one for each) and another put the arguments into an array, and then pass this array to the method. Both of them are potentially error-prone and require more code.
Since there are two possibilities, it causes ambiguity. Because of this, sometimes you may need to use two different method names instead of overloading the varargs method. What is varargs?
In order to define vararg, ... (three dots) is used in the formal parameter of a method. A method that takes variable number of arguments is called a variable-arity method, or simply a varargs method. As you can clearly see, you had to overload sumNumber () method to make it work for 3 arguments.
A method can have only one varargs parameter. In the above program, the compiler gets confused if you try to invoke the test () method even though test () methods are overloaded and accepts different number of arguments. The compiler doesn’t know which method to call.
It looks like you've tricked yourself here:
Object os = new Object[]{1,2,3};
System.out.println(os);
f(os);
Since os
is typed as Object
, it gets interpreted as the first element of the varargs array. What gets passed into the method is actually a new Object[]
whose single element is your Object[]
.
If you do the following, it will print the same instance:
Object[] os = new Object[]{1,2,3};
System.out.println(os);
f(os);
The f
method will need make a defensive copy of the array itself in order to guarantee that an array passed in by the caller isn't modified. As arshajii points out, varargs are foremost array parameters, with the "bonus" behavior of creating a new array when given an argument list.
Anyway you can use Arrays.copyOf
to make the copy, which delegates to (the less type-safe) System.arraycopy
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With