If I understand it correctly, Integer[] is a subtype of Object[]. You can for instance do
Object[] objs = new Integer[] { 1, 2, 3 };
While playing around with var-args I realized, that it seems like the compiler “over approixmates” the array type for no obvious reason.
The program below for instance, prints 123 123. Wouldn’t it make sense / be more precise if it printed 123 6?
class Test {
public static Object combine(Object... objs) {
if (objs instanceof Integer[]) {
int sum = 0;
for (Integer i : (Integer[]) objs)
sum += i;
return sum;
} else {
String concat = "";
for (Object o : objs)
concat += o;
return concat;
}
}
public static void main(String[] args) {
System.out.println(combine("1", "2", "3")); // prints 123
System.out.println(combine(1, 2, 3)); // prints 123
}
}
I guess my question could be summed up as: Would any contradiction / problem arise if the JLS was defined to pass T[] as argument, where T was the least upper bound of the types of all arguments given?
Edit: I realize that I, in this particular case, could overload the the combine method to take Integer[] as well (ideone demo). Still, the question remains of why this design was chosen.
As to this specific question:
Yes, because the array is not read-only; it’s writable:
which prints
If the JLS was defined the way you are asking (e.g. for
foo(T... args), if you callfoo(a,b,c)then the compiler constructs an array of the least upper bound of the types a,b,c), then this case would allow a runtime error: the invocation ofchangeLastArgument(1,2,3)would create an array of typeInteger[], but thechangeLastArgument()method would attempt to assign"Pow!"to the last element and you’d get a runtime error.The declaration of
changeLastArgument()is specifying its input types, and therefore it should be able to assume its input argument is truly anObject[]and not a subtype ofObject[], so that it can safely modify the input arguments. (This is similar to the PECS principle — in order for aList<T>to be both safely readable and writable, you can’t use any wildcards likeList<? extends T>— which is safely readable but not safely writable — orList<? super T>— which is safely writable but not safely readable.)