简体   繁体   中英

Compare two generic types in Java?

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're trying to compare the contents of two lists, then you shouldn't implement the type comparison yourself. Instead you should do this:

    public static <U, V> boolean isEqual(List<U> a, List<V> b) {
        if (a.size() != b.size()) 
            return false;
        for (int i = 0; i < a.size(); i++)
            if (!a.get(i).equals(b.get(i)))
                return false;
        return true;
    }

This way you're relying on the types U and V to be able to handle equals() properly. Here's some guidelines on implementing equals(): http://www.javaworld.com/article/2072762/java-app-dev/object-equality.html

What I'm guessing you want to do is to be able to return quickly in case the types are different. But with implementation I gave you, you'll get the same behaviour -- you'll return on the first iteration.

Do not rely on

a.getClass().equals(b.getClass())

This is not correct, it will only check whether both are of type ArrayList and not String, Integer etc.

Try this only

a.get(0).getClass().equals(b.get(0).getClass())

Make sure you check null condition, otherwise you will encounter NullPointerException here.

我想你想检查a == b而不是U == V.在这种情况下,你必须编写自己的比较方法来比较U和V类的实例。

Assuming a and b are not null and not empty,

a.get(0).getClass().equals(b.get(0).getClass())

should do the trick.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM