I was trying to fix a Problem with an unknown Comparator (no Source access). So I've wrote some Reflection Code to see what Types that Comparator accepts.
Surprisingly, Reflection tells me, there are two compare-Methods, one with the real type and one with Object:
Comparator<Integer> comp = new Comparator<Integer>()
{
@Override
public int compare(Integer o1, Integer o2)
{
return 0;
}
};
Method[] methods = comp.getClass().getMethods();
for (Method method : methods)
{
if(method.getName().equals("compare")){
System.out.println(method);
}
}
Output:
public int de.hinneLinks.stackoverflow.MyClass$1.compare(java.lang.Integer,java.lang.Integer)
public int de.hinneLinks.stackoverflow.MyClass$1.compare(java.lang.Object,java.lang.Object)
Where is that second compare
Method coming from?
But its not usable, why?:
comp.compare(1, 2); //Compiles
comp.compare((Object)1,(Object)2); //Does not Compile
I can however call those Methods with Reflection, if i call both Methods with new Object()
, i'll get two different Exceptions:
compare(java.lang.Object,java.lang.Object)
java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.Integer
compare(java.lang.Integer,java.lang.Integer)
java.lang.IllegalArgumentException: argument type mismatch
If define my Comparator with Object, then there is only one Method.
The other method (compare(Object obj1, Object2
) is a bridge method generated by the compiler to preserve binary compatibility after type erasure:
When compiling a class or interface that extends a parameterized class or implements a parameterized interface, the compiler may need to create a synthetic method, called a bridge method, as part of the type erasure process. You normally don't need to worry about bridge methods, but you might be puzzled if one appears in a stack trace.
You can add a check on the method to see if it's a bridge method:
for (Method method : methods) {
if (method.getName().equals("compare") && !method.isBridge()) {
System.out.println(method);
}
}
This is due to Type Erasure, which was a design decision (preserving backwards-compatibility) in the implementation of Generics in Java.
During the type erasure process, the Java compiler erases all type parameters and replaces each with its first bound if the type parameter is bounded, or Object if the type parameter is unbounded.
This allows your class to be accessed from pre-Java-5 JVMs, where Comparator<Integer>
isn't visible but Comparator
is (where it supplies compare(Object, Object)
). The implementation of compare(Object, Object)
simply casts each argument to an Integer and calls compare(Integer, Integer)
, which is why you get your exceptions.
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