我正在尝试修复未知比较器的问题(无源访问)。 所以我写了一些反射代码来看看比较器接受的类型。
令人惊讶的是,Reflection告诉我,有两个比较方法,一个是真实类型,另一个是对象:
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);
}
}
输出:
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)
第二个compare
方法来自哪里?
但它不可用,为什么?:
comp.compare(1, 2); //Compiles
comp.compare((Object)1,(Object)2); //Does not Compile
我可以用反射调用那些方法,如果我用new Object()
调用两个方法,我会得到两个不同的异常:
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
如果使用Object定义我的Comparator,则只有一个Method。
答案 0 :(得分:6)
另一种方法(compare(Object obj1, Object2
)是编译器生成的bridge method,用于在类型擦除后保留二进制兼容性:
在编译扩展参数化类或实现参数化接口的类或接口时,编译器可能需要创建一个合成方法,称为桥接方法,作为类型擦除过程的一部分。您通常不需要担心桥接方法,但如果出现在堆栈跟踪中,您可能会感到困惑。
您可以添加方法检查以查看它是否为桥接方法:
for (Method method : methods) {
if (method.getName().equals("compare") && !method.isBridge()) {
System.out.println(method);
}
}
答案 1 :(得分:3)
这是由于Type Erasure,这是Java中泛型实现的设计决策(保留向后兼容性)。
在类型擦除过程中,Java编译器会擦除所有类型参数,如果type参数是有界的,则将每个参数替换为第一个绑定,如果type参数是无界的,则替换为Object。
这允许从Java-5之前的JVM访问您的类,其中Comparator<Integer>
不可见但Comparator
是{它提供compare(Object, Object)
的地方)。 compare(Object, Object)
的实现只是将每个参数强制转换为整数并调用compare(Integer, Integer)
,这就是为什么你会得到例外。