Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compare two generic types in Java?

Tags:

java

generics

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.

like image 608
Mahmoud Hanafy Avatar asked Jan 22 '16 16:01

Mahmoud Hanafy


2 Answers

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.

like image 165
Tunaki Avatar answered Sep 30 '22 07:09

Tunaki


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>.

like image 38
Captain Man Avatar answered Sep 30 '22 07:09

Captain Man