Reputation: 55
Consider the following code
/**
* Generic method with bounds
*/
public static <T> int countGreaterThan(Comparable<T>[] anArray,
T elem) {
int count = 0;
for (Comparable<T> e : anArray)
if (e.compareTo(elem) > 0)
++count;
return count;
}
/**
* Alternative to above
*/
public static <T extends Comparable<T>> int countGreaterThan(T[] anArray, T elem) {
int count = 0;
for (T e : anArray)
if (e.compareTo(elem) > 0)
++count;
return count;
}
It appears that both are functionally the same. However they can appear in the same class apparently overloading each other. When I use the following code, it seems the second method gets invoked. Without the second overloading method, the first method get invoked. Can someone provide an in-depth explanation?
Integer[] array = new Integer[10];
for (int i = 0; i < array.length; ++i)
array[i] = i;
System.out.println("Count > 5 = " + countGreaterThan(array, 5));
Upvotes: 2
Views: 101
Reputation: 66886
(They can appear in the same class since they don't have the same erasure. The first one has a first argument of type Comparable[]
and the second of type Object[]
.)
Both methods could apply; in Java, the method to call is determined at compile time and is always the more-specific overloading based on the argument's reference type.
Carlo Pellegrini makes a good point that the first would be called for any old Comparable
. Greater experts may correct me, but I am fairly sure this is due to boxing. The call in your example binds Integer[]
to T[]
first, and then this induces the boxing of int
to T
which is now reified as Integer
. In the case of his example Y
, it can only match the first one.
Upvotes: 1
Reputation: 5686
Well, it's not a complete erasure.
The first method
<T> int countGreaterThan(Comparable<T>[] anArray,T elem)
works on an array of Comparable<T>
, but does not mandate that elem
is also Comparable
.
You could check it on:
static class Y {
int val;
public Y(int val){
this.val=val;
}
}
static class W extends Y implements Comparable<Y>{
public W(int val){
super(val);
}
public int compareTo(Y o){
return this.val-o.val;
}
}
W[] array = new W[10];
for (int i = 0; i < array.length; ++i)
array[i] = new W(i);
System.out.println("Count > 5 = " + countGreaterThan(array, new Y(5)));
The first method will be called.
Upvotes: 2
Reputation: 691973
That's because in Java, an Integer[]
is also a Comparable[]
. If you had the same method with a list instead of an array as arguments, it wouldn't work the same way, because a List<Integer>
is not a List<Comparable>
. So only the second version would accept a List<Integer>
as argument.
Collections are more type-safe and work better with generics than arrays. You should prefer them over arrays in general.
Upvotes: 0