Reputation: 8386
Consider the following scenario:
<T> void function(T...args){
...code...
}
And then I call it using a Integer[]
. How does the compiler assume that T
is an Integer
, and not a Integer[]
? (Note, I'm glad that this is the case, but I still find the ambiguity odd).
Furthermore, if I wanted T
to be Integer[]
, is there anyway for me to do that (assuming boxing/unboxing doesn't exist)?
Upvotes: 2
Views: 235
Reputation: 122429
Note that Generics isn't completely relevant to the question. The exact same question would apply if the function signature were void function(Object... args)
-- if you pass an expression of type Integer[]
, it could interpreted as either using the array as args
, or as one of the elements of args
.
The answer is that, basically, the compiler will prefer to use the argument as args
if possible. Since the expression you are passing has "array of reference type" type, it is compatible with args
, and therefore, that interpretation prevails.
Furthermore, if I wanted T to be Integer[], is there anyway for me to do that (assuming boxing/unboxing doesn't exist)?
Since it is a generic method, you can explicitly specify the the type argument when calling: this.<Integer[]>function(...)
.
But back to the more general question where the function signature is void function(Object... args)
. You could explicitly create the array of arguments yourself:
function(new Integer[][]{ myIntegerArray });
or (simpler) you can cast the expression to a type that is no longer an array of reference type:
function((Object)myIntegerArray);
Upvotes: 0
Reputation: 19682
There are 3 phases in finding the applicable methods. On the 1st phase, javac tries to match argument types and method parameter types exactly. The parameter type of the method is T[]
on this phase, the argument type is Integer[]
, the two matche after T
is inferred to be Integer
, therefore the method is chosen as the applicable method (there are no other overloading methods to consider). No further phases are carried out.
If the 1st phase does not yield an applicable method, javac will continue to other phases. For example, if T
is explicitly specified as Integer[]
, the method will not match on the 1st phase (because T[]
would not match Integer[]
)
On the 3rd phase, varargs are considered; javac will match T
, not T[]
, with trailing argument types.
This is indeed, quite confusing, and appear to be ambiguous to our intuition.
Upvotes: 1
Reputation: 56536
The Java compiler is smart enough to know that, since you gave it an Integer[]
, you probably meant for T
to be Integer
, not Integer[]
. I'd assume this is part of the Java language specification that defines ...
as varargs.
If you want to specify what T
is, you can do that with the following syntax:
Integer[] ary = { 1, 2, 3 };
myObj.function(ary); // T is Integer
myObj.<Integer>function(ary); // T is Integer
myObj.<Integer[]>function(ary); // T is Integer[]
<Integer>function(ary); // this is invalid; instead you could do...
this.<Integer>function(ary); // this if it's an instance method
MyClass.<Integer>function(ary); // or this if it's static
Upvotes: 2
Reputation: 85779
Generics works on object references, so <T>
will work on object references of a class. int[]
is a class that references an array of int
, while int
is a primitive. Integer[]
is a class that references to an array of Integer
, where Integer
is another class.
After reviewing this, the varargs param T ... args
expects an array of object references, so int[]
would be a single element in the array of object references, while Integer[]
is an array of object references.
If you want to send an Integer[]
as each element of your varargs, you can send an Integer[][]
. I wrote an example:
public class SomeMain {
static <T> void foo(T...ts) {
for(T t : ts) {
System.out.println(t);
}
System.out.println();
}
public static void main(String[] args) {
int[] ints = { 1, 2, 3 };
Integer[] integers = { 1, 2, 3 };
foo(ints);
foo(integers);
//note, here each element in the varags will behave as Integer[]
foo(new Integer[][] { integers });
}
}
Output (the hash code of the array will change on every run):
[I@8dc8569
1
2
3
[Ljava.lang.Integer;@45bab50a
Upvotes: 1