compareTo with generic arguments is giving warning - java

I want to compare two arguments in less method which are of type Comparable. But if I use comapreTo it is giving me error in type casting:
private boolean less(Comparable<T> u, Comparable<T> v) {
return u.compareTo(v) < 0;
}
I fixed the issue by type casting the argument passed into compareTo. But still it is giving me warning (Type safety: Unchecked cast from Comparable to T). Why is it so. Am I doing something wrong. What is the best way to achieve this.
private boolean less(Comparable<T> u, Comparable<T> v) {
return u.compareTo((T) v) < 0;
}

Since u has type Comparable<T>, u.compareTo() takes a T. You're passing it v, a Comparable<T>, which is not compatible.
You might be assuming in your mind that a type that implements Comparable is comparable to itself. But there is no such requirement on a technical level. It's perfectly legal for me to make a type Foo, that is Comparable<Bar>, i.e. it compares to Bar, where Foo and Bar are completely unrelated. Trying to pass a Foo into a Foo object's compareTo will crash.
If you want to make a constraint that the two arguments are of the same type which is comparable to itself, you would do something like
private <T extends Comparable<? super T>> boolean less(T u, T v) {
return u.compareTo(v) < 0;
}
However, for the purposes of this function, the constraint that the two arguments are of the same type is not technically necessary (although it should be true in all normal use cases). And in generics we always want to use the least restrictive bound possible, which is, as other answers have mentioned,
private <T> boolean less(Comparable<T> u, T v) {
return u.compareTo(v) < 0;
}
In your comments, you mentioned you are comparing elements from a Comparable<T>[]. That is not a type of array that allows you to compare elements from. You just know that it's an array of elements that are comparable to a certain T, but not comparable to themselves. Much more useful would be to have a T[], where T has a bound that it is comparable to itself:
class Whatever<T extends Comparable<? super T>> {
//...
T[] yourArray;
}

The initial error is correct, and the warning is correct to: your trick is very unsafe: you can't cast v to T.
Because your method takestwo parameters u and v, each one is an instance of a class, which implements compareTo ( some instance of T).
precisely: u can compare to T, v can compare to T.
But, inside, you want to compare u and v. There is absolutely no garantee you can do it.
This, for example, is correct:
private static <X> boolean less(Comparable<X> u, X v)
{
return u.compareTo(v) < 0;
}

Related

Java generic T extends Object

Given the following class:
public class TestMap<K,V> {
private HashMap<K,V> map;
public void put(K k, V v) {
map.put(k, v);
}
public V get(K k) {
return map.get(k);
}
}
and this function:
static<T extends Object> String getObj(TestMap<T, String> m, String e) {
return m.get(e);
}
Why does "get" show this error:
The method get(T) in the type MyHashMap<T,String> is not applicable for the arguments (String)
When getObj states T extends Object, and the map has been initialized with TestMap<T, String> m, why can't String be used as parameter? I cant wrap my head around why this doesnt work, as String is a subtype of Object ?
I tried extending T from a custom superclass and using a subclass instead of String.
get() requires as an argument a key, which is of type T, not String.
So either you need to change e to type T or change the type of the Map, e.g., to TestMap<String, T>.
Generics describe what an Object is, List<String> strings is a list of Strings. That gives us some convenience, we don't have to cast. String s = strings.get(0); and we get some compile-time protection. Integer i = 1; then strings.add(i); fails to compile.
The error you are getting is a compile time protection. The key you're providing is an Object, so it might be the correct type. In the case of a map, "why not check?" It is just going to hashcode and check for equality which is ok. In the case of a List though, strings.add((Object)i); needs to fail.
If the doesn't fail, then later something might call. for(String s: strings) and get a class cast exception.
To fix this you can change you V get(K k) method to a V get(Object k) the same as map uses. Your get method requires type K a map normally has a get method with a Object
As mentioned "T extends Object" is the same as just "T". You use the extends when you want to put a lower bound on something. public <T extends Number> int sum(List<T> numbers). In this case "T" can be any class that extends numbers. We can do Number n = numbers.get(0); because we know it is at least a number. But we could not do numbers.add(n); because while T is at least a number, it could be something else like an Integer, Double, Number, BigDecimal etc.

Generic Comparable type for compareTo

I have a method called getMember which may return any Comparable object, String, Integer etc.
I can't figure out what to use as type parameter so compareTo will work. Code below is not working
Comparable<? extends Comparable<?>> m1 = column.getMember(o1);
Comparable<? extends Comparable<?>> m2 = column.getMember(o2);
int compareTo = m1.compareTo(m2);
In case I wasn't clear, m1 and m2 will always be same type. Comparing without type parameters works fine, I just wanted to know what to put in <>
I think what you need here is a generic method. Whatever method this section of code is in must be generified. Here's my best shot, in absence of your source for the getMember method.
public <T extends Comparable<? super T>> void doSomethingTheOPWants() {
...
T m1 = column.getMember(o1);
T m2 = column.getMember(o2);
int compareTo = m1.compareTo(m2);
}
With my current knowledge of the code, I don't think I can create a relevant/worthwhile test, so I'll leave that up to OP.

Wild card in java Generic and <? super T> meaning, lower or upper bound

So I am reading about generic method and I am get confused. Let me state the problem here first:
In this example: Suppose that I need a version of selectionSort that works for any type T, by using an external comparable supplied by the caller.
First attempt:
public static <T> void selectionSort(T[] arr, Comparator<T> myComparator){....}
Suppose that I have:
Defined vehicle class
created VehicleComparator implementing Comparator while
compare vehicles by their price.
created Truck extends vehicle
instantiated Truck[] arr ; VehicleComparator myComparator
Now, I do:
selectionSort(arr, myComparator);
and it won't work, because myComparator is not available for any subclass of Vehicle.
Then, I do this:
public static <T> void selectionSort(T[] arr, Comparator<? super T> myComparator){....}
This declaration will work, but I don't completely sure what I've been doing... I know use is the way to go. If "? super T" means "an unknown supertype of T", then am I imposing a upper or lower bound? Why is it super? My intention is to let any subclass of T to use myComparator, why "? super T". So confused... I'd appreciate if you have any insight in this..
Thanks ahead!
Firstly, you could have solved it by having Vehicle[] which you then added Trucks to.
The reason you need <? super T> goes back to the generics rule that Comparator<Truck> is not a subtype of Comparator<Vehicle>; the unbounded type T must match exactly, which it doesn't.
In order for a suitable Comparator to be passed in, it must be a Comparator of the class being compared or any super class of it, because in OO languages any class may be treated as an instance of a superclass. Thus, it doesn't matter what the generic type of the Comparator is, as long as it's a supertype of the array's component type.
The quizzical phrase ? super T means that the destination list may have elements of any type
that is a supertype of T, just as the source list may have elements of any type that is a
subtype of T.
We can see pretty simple example copy from Collections:
public static <T> void copy(List<? super T> dst, List<? extends T> src) {
for (int i = 0; i < src.size(); i++) {
dst.set(i, src.get(i));
}
}
And call:
List<Object> objs = Arrays.<Object>asList(2, 3.14, "four");
List<Integer> ints = Arrays.asList(5, 6);
Collections.copy(objs, ints);
assert objs.toString().equals("[5, 6, four]");
As with any generic method, the type parameter may be inferred or may be given explicitly. In this case, there are four possible choices, all of which type-check and all of which have the same effect:
Collections.copy(objs, ints);
Collections.<Object>copy(objs, ints);
Collections.<Number>copy(objs, ints);
Collections.<Integer>copy(objs, ints);
Your method signature
public static <T> void selectionSort(T[] arr, Comparator<? super T> myComparator)
means that if you invoke it with an array of type T than you must also provide a Comparator of type T or a super type of T.
For example if you have the following classes
class Vehicle {}
class Truck extends Vehicle {}
class BigTruck extends Truck {}
class VehicleComparator implements Comparator<Vehicle> {
public int compare(Vehicle o1, Vehicle o2) {
return 0;
}
}
class BigTruckComparator implements Comparator<BigTruck> {
public int compare(BigTruck o1, BigTruck o2) {
return 0;
}
}
class TruckComparator implements Comparator<Truck> {
public int compare(Truck o1, Truck o2) {
return 0;
}
}
then this will work
Truck[] trucks = ...;
selectionSort(trucks, new TruckComparator());
selectionSort(trucks, new VehicleComparator());
Because
TruckComparator implements Comparator<Truck> and a Truck is equal to the array's type Truck
VehicleComparator implements Comparator<Vehicle> and a Vehicle is a super type of the array's type Truck
This will NOT WORK
selectionSort(trucks, new BigTruckComparator());
Because a BigTruckComparator is a Comparator<BigTruck> and a BigTruck is not a super type of the array's type Truck.
The two signatures are equivalent in terms of power -- for any set of arguments, if there exists a choice of type arguments that works for one of them, there exists a choice of type arguments that works for the other one, and vice versa.
You are simply running into limited inference in your compiler. Simply explicitly specify the desired type argument:
YourClass.<Vehicle>selectionSort(arr, myComparator);

Java Generics - are these two method declarations equivalent?

Given some class SomeBaseClass, are these two method declarations equivalent?
public <T extends SomeBaseClass> void myMethod(Class<T> clz)
and
public void myMethod(Class<? extends SomeBaseClass> clz)
For the caller: yes, they are equivalent.
For the code inside the method: no.
The difference is that within the code of the first example you can use the type T (for example to hold an object created by clz.newInstance()), while in the second you can't.
No, they're not. With the first definition, you can use the type T inside the method definition, e.g. create an ArrayList<T> or return T. With the second definition, that's not possible.
Bounded wildcards are subject to certain restrictions to avoid heap pollution.
When you use the wildcard ? extends X you know you can read generic information, but you cannot write.
For instance
List<String> jedis = new ArrayList<String>();
jedis.add("Obiwan");
List<? extends CharSequence> ls = jedis
CharSequence obiwan = ls.get(0); //Ok
ls.add(new StringBuffer("Anakin")); //Not Ok
The compiler avoided heap pollution when you tried to add a CharSequence (i.e. StringBuffer) to the collection. Because the compiler cannot be sure (due to wildcards) that the actual implementation of the collection is of type StringBuffer.
When you use ? super X you know you can write generic information, but you cannot be sure of the type of what you read.
For instance
List<Object> jedis = new ArrayList<Object>();
jedis.add("Obiwan");
List<? super String> ls = jedis;
ls.add("Anakin"); //Ok
String obiwan = ls.get(0); //Not Ok, we canĀ“t be sure list is of Strings.
In this case, due to wildcards, the compiler knows that the actual implementation of the collection could be anything in the ancestors of String. Thus it cannot guarantee that what you will get will be a String. Right?
This same restrictions are the ones you would be subject too in any declaration with bounded wildcards. These are typically known as the get/put principle.
By using a type parameter T you change the story, from the method standpoint you are not using a bounded wildcard but an actual type and therefore you could "get" and "put" things into instances of the class and the compiler would not complain.
For instance, consider the code in Collections.sort method. If we write a method as follows, we would get a compile error:
public static void sort(List<? extends Number> numbers){
Object[] a = numbers.toArray();
Arrays.sort(a);
ListIterator<? extends Number> i = numbers.listIterator();
for (int j=0; j<a.length; j++) {
i.next();
i.set((Number)a[j]); //Not Ok, you cannot be sure the list is of Number
}
}
But if you write it like this, you can do the work
public static <T extends Number> void sort(List<T> numbers){
Object[] a = numbers.toArray();
Arrays.sort(a);
ListIterator<T> i = numbers.listIterator();
for (int j=0; j<a.length; j++) {
i.next();
i.set((T)a[j]);
}
}
And you could even invoke the method with collections bounded with wildcards thanks to a thing called capture conversion:
List<? extends Number> ints = new ArrayList<Integer>();
List<? extends Number> floats = new ArrayList<Float>();
sort(ints);
sort(floats);
This could not be achieved otherwise.
In summary, as others said from the caller standpoint they are alike, from the implementation standpoint, they are not.
No. On top of my head, I can think of the following differences:
The two versions are not override-equivalent. For instance,
class Foo {
public <T extends SomeBaseClass> void myMethod(Class<T> clz) { }
}
class Bar extends Foo {
public void myMethod(Class<? extends SomeBaseClass> clz) { }
}
does not compile:
Name clash: The method myMethod(Class) of type Bar has the same erasure as myMethod(Class) of type Foo but does not override it
If a type parameter appears more than once in a method signature, it always represents the same type, but if a wildcard appears more than once, each occurrence may refer to a different type. For instance,
<T extends Comparable<T>> T max(T a, T b) {
return a.compareTo(b) > 0 ? a : b;
}
compiles, but
Comparable<?> max(Comparable<?> a, Comparable<?> b) {
return a.compareTo(b) > 0 ? a : b;
}
does not, because the latter may be called by
max(Integer.MAX_VALUE, "hello");
The method body may refer to the actual type used by the caller using a type parameter, but not using a wildcard type. For instance:
<T extends Comparable<T>> T max(T... ts) {
if (ts.length == 0) {
return null;
}
T max = ts[0];
for (int i = 1; i < ts.length; i++) {
if (max.compareTo(ts[i]) > 0) {
max = ts[i];
}
}
return max;
}
compiles.
#Mark #Joachim #Michael
see the example in JLS3 5.1.10 Capture Conversion
public static void reverse(List<?> list) { rev(list);}
private static <T> void rev(List<T> list){ ... }
so the <?> version can do anything the <T> version can do.
this is easy to accept if the runtime is reified. a List<?> object must be a List<X> object of some specific non-wildcard X anyway, and we can access this X at runtime. So there's no difference using a List<?> or a List<T>
With type erasure, we have no access to T or X, so there's no difference either. We can insert a T into a List<T> - but where can you get a T object, if T is private to the invocation, and erased? There are two possibilities:
the T object is already stored in the List<T>. so we are manipulating elements themselves. As the reverse/rev example shows, there's no problem doing this to List<?> either
it comes out-of-band. There's other arrangement made by the programmer, so that an object somewhere else is guaranteed to be of type T for the invocation. Unchecked casting must be done to override compiler. Again, no problem to do the same thing to List<?>

Java Generics: compareTo and "capture#1-of ?"

The following gives me an error message:
public static List<Comparable<?>> merge(Set<List<Comparable<?>>> lists) {
List<Comparable<?>> result = new LinkedList<Comparable<?>>();
HashBiMap<List<Comparable<?>>, Integer> location = HashBiMap.create();
int totalSize;
for (List<Comparable<?>> l : lists) {
location.put(l, 0);
totalSize += l.size();
}
boolean first;
List<Comparable<?>> lowest; //the list with the lowest item to add
int index;
while (result.size() < totalSize) {
first = true;
for (List<Comparable<?>> l : lists) {
if (! l.isEmpty()) {
if (first) {
lowest = l;
}
else if (l.get(location.get(l)).compareTo(lowest.get(location.get(lowest))) <= 0) { //error here
lowest = l;
}
}
}
index = location.get(lowest);
result.add(lowest.get(index));
lowest.remove(index);
}
return result;
}
The error is:
The method compareTo(capture#1-of ?) in the type Comparable<capture#1-of ?> is not applicable for the arguments (Comparable<capture#2-of ?>)
What's going on here? I made the type of everything Comparable so I could call .compareTo and sort this list. Am I using generics incorrectly?
List<?> means "List of anything", so two objects with this type are not the same: One could be a list of String, the other a list of BigDecimal. Obviously, those are not the same.
List<T> means "List of anything but when you see T again, it's the same T".
You must tell the compiler when you mean the same type in different places. Try:
public static <T extends Comparable<? super T>> List<T> merge(Set<List<T>> lists) {
List<T> result = new LinkedList<T>();
HashBiMap<List<T>, Integer> location = HashBiMap.create();
[EDIT] So what does <T extends Comparable<? super T>> List<T> mean? The first part defines a type T with the following properties: It must implement the interface Comparable<? super T> (or Comparable<X> where X is also defined in terms of T).
? super T means that the type which the Comparable supports must T or one of its super types.
Imagine for a moment this inheritance: Double extends Integer extends Number. This is not correct in Java but imagine that Double is just an Integer plus a fraction part. In this scenario, a Comparable which works for Number also works for Integer and Double since both derive from Number. So Comparable<Number> would satisfy the super part for T being Number, Integer or Double.
As long as each of these types support the Comparable interface, they also satisfy the first part of the declaration. This means, you can pass in Number for T and the resulting code will also work when there are Integer and Double instances in the lists. If you Integer for T, you can still use Double but Number is not possible because it doesn't satisfy T extends Comparable anymore (the super part would still work, though).
The next step is to understand that the expression between static and List just declares the properties of the type T which is used later in the code. This way, you don't have to repeat this long declaration over and over again. It's part of the behavior of the method (like public) and not part of the actual code.

Categories