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.
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.
I think you would like to check whether a == b instead of U == V. In that case you have to write your own compare method to compare the instance of class U and V.
Assuming a and b are not null and not empty,
a.get(0).getClass().equals(b.get(0).getClass())
should do the trick.