I have the following method:
public <U, V> boolean isEqual(List<U> a, List<V> b) {
    // check if U == V
}
I want to check if U and V are the same classes.
You can't do that because of type erasure, it is that simple.
Consider the following:
public static void main(String[] args) {
    List<? extends Number> l1 = Arrays.asList(1L, 2, 3L);
    List<? extends Number> l2 = Arrays.asList(1);
    isEqual(l1, l2);
}
public static <U, V> boolean isEqual(List<U> a, List<V> b) {
    // is U == V here?
}
Is U == V here? l1 contains Long and Integer instances but l2 contains a single Integer instance.
I'm guessing from your comment:
The first condition should be that their type are the same
that what you should have instead is a single type U. In this case, use the following signature:
public static <U> boolean isEqual(List<U> a, List<U> b) {
}
and with that, the above code won't compile anymore.
What you could also do is add 2 parameters accepting the classes:
public static <U, V> boolean isEqual(List<U> a, List<V> b, Class<U> uClass, Class<V> vClass) {
    if (!uClass.equals(vClass)) {
        // classes are different
    }
}
In this case, you can print a message if the classes given are not the same.
If you are making your own class you can require that Class<T> be included in the constructor as demonstrated here
Ex:
public class SomeClass<T> {
    private final Class<T> clazz;
    public SomeClass(Class<T> clazz) {
        this.clazz = clazz;
    }
    public Class<T> getParam() {
        return clazz;
    }
}
Now you can call SomeClass#getParam() to get the type param declared.
There is also a way to do this with reflection.
All this said, the reason you have to do weird work-arounds to this is because of Type Erasure. Basically at runtime Java sees all generics as Object, so while compiling your List may be a List<Integer> or List<Boolean>, but at runtime they're both List<Object>.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With