Reputation: 63
I'm trying to write a utility function to the Array class.
The function should return the minimum element for all kinds of comparable types.
My question is which signature should the function has:
public static <E> E min (Comparable**<E>**[] arr)
public static <E> E min (Comparable**<? super E>**[] arr)
In Java arrays are variants and that means that if B extends A so A[] and B[] are related too, but ArrayList<A>
and ArrayList<B>
don't have the same connection.
This is the full code:
@SuppressWarnings("unchecked")
public static <E> E min (Comparable<E>[] arr){
E min= null;
if(arr.length > 0)
min = (E) arr[0];
for (int i = 1; i < arr.length; i++) {
if( (arr[i].compareTo((E) min)) < 0)
min = (E) arr[i];
}
return min;
}
Comment: I have two class A
implements Comparable
A
and B
extends A
When the signature is Comparable<? super E>
then the call (from main) to:
A aArr[] = new A[] {new A(1), new B(2), new B(-1)};
B bb = min(aArr);
is a compiling error: cannoot convert from ...A to ... B
, but when the signature of min() is Comparable<? super E>
then the same call is just fine.
Thanks
Upvotes: 0
Views: 159
Reputation: 272685
Neither of the signatures is a "correct" signature for this method, IMO. The correct signature is to accept a E[]
, where E extends Comparable<? super E>
:
public static <E extends Comparable<? super E>> E min (E[] arr){
E min= null;
if(arr.length > 0)
min = arr[0];
for (int i = 1; i < arr.length; i++) {
if( (arr[i].compareTo(min)) < 0)
min = arr[i];
}
return min;
}
Your current implementation makes an incorrect assumption that "classes that implement Comparable<T>
must be T
or a subclass of T
". This is not necessarily true. This is why you have to suppress those warnings.
Anyway, back to your actual problem. At the caller's side, you are doing B bb = min(aArr)
. In the Comparable<E>
case, the error appears because the compiler could not infer what E
should be. It can't be A
because A
can't be assigned to a variable of type B
. It can't be B
either, because you are giving it a A[]
, which is not a Comparable<B>[]
.
When you changed it to Comparable<? super E>
, E
can be B
now. Since A[]
is compatible with Comparable<? super B>
.
But this only works in a really "hacky" way, because you are technically casting every element in the array to a B
, since E
is B
, and because of how Java generics are erased, this doesn't fail.
The root of your problem really lies in the line B bb = min(aArr)
. You are making a possibly wrong assumption that the minimum of aArr
is of type B
. Why are you so sure? It could be an A
as well, right? With my solution above, you need to cast the result to B
if you are so sure that it is B
:
B bb = (B)min(aArr);
Upvotes: 0
Reputation: 3236
The second signature works because A is superclass of class B, whereas it suits wildcard condition ? super B
.
If you want your function to return minimum value of any comparable typed array, you just need.
public static <E extends Comparable<E>> min (E[] arr)
This will allow you to use the method for operating all kind of arrays, values of which have comparable type. In your case, you want A and B to be related. So you should also allow your method to take parameter of class E and it's superclasses. However, it is only needed, when you try to cast A to B, as in your example. That makes you want your method to take superclasses of E (as A is superclass of B) and still return value of type E.
public static <E extends Comparable<? super E>> min (E[] arr)
Upvotes: 1