How is it possible that following code even compiles? As far as I can see the count function is called with two different types, yet compiler doesn't complain and happily compiles this code.
public class Test {
public static <T> int count(T[] x,T y){
int count = 0;
for(int i=0; i < x.length; i++){
if(x[i] == y) count ++;
}
return count;
}
public static void main(String[] args) {
Integer [] data = {1,2,3,1,4};
String value = "1";
int r =count(data,value);
System.out.println( r + " - " + value);
}
}
By passing two objects at once you are putting up too many constraints on
T
. This "forces" the compiler to inferObject
. Luckily there's a simple workaround -- only pass one object. The following will produce the expected error.Types are not so different - both are subclasses of java.lang.Object. So compiler assumes T is Object in this case.
If you change your call to:
You will see the compiler complain.
T
gets coerced upwards toObject
. TheInteger[]
can be upcasted toObject[]
, and theString
gets upcasted toObject
, and it typechecks.In this case the
T
is useless. You can change the signature topublic static int count(Object[] x, Object y)
without any effect on what arguments the compiler will let it accept. (You can see that the signature forArrays.fill()
uses that as the signature.)If we consider the simpler case, where you just have arguments of type
T
, you can see that, since any instance ofT
is also an instance of its superclasses,T
can always to be inferred to be its upper bound, and it will still accept the same argument types as before. Thus we can get rid ofT
and use its upper bound (in this caseObject
) instead.Arrays in Java work the same way: arrays are covariant, which means that if
S
is a subclass ofT
,S[]
is a subclass ofT[]
. So the same argument as above applies -- if you just have arguments of typeT
andT[]
,T
can be replaced by its upper bound.(Note that this does not apply to generic types, which are not covariant or contravariant:
List<S>
is not a subtype ofList<T>
.)