比较器二将方法与反射进行比较



我试图修复一个未知比较器的问题(没有源访问权限)。所以我写了一些反射代码来看看比较器接受什么类型。

令人惊讶的是,Reflection告诉我,有两种比较方法,一种是真正类型,另一种是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);
    }
}

输出:

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,那么只有一个方法。

另一个方法(compare(Object obj1, Object2)是编译器生成的桥接方法,用于在类型擦除后保持二进制兼容性:

当编译扩展参数化类或实现参数化接口的类或接口时,编译器可能需要创建一个合成方法,称为桥接方法,作为类型擦除过程的一部分。您通常不需要担心桥接方法,但如果在堆栈跟踪中出现桥接方法,您可能会感到困惑。

你可以在方法上添加一个检查,看看它是否是一个桥接方法:

for (Method method : methods) {
    if (method.getName().equals("compare") && !method.isBridge()) {
        System.out.println(method);
    }
}

这是由于类型擦除,这是Java中泛型实现中的一个设计决策(保留向后兼容性)。

在类型擦除过程中,如果类型参数是有界的,Java编译器将擦除所有类型参数,并将每个类型参数替换为其第一个绑定;如果类型参数为无界的,则替换为Object。

这允许从Java-5之前的JVM访问类,其中Comparator<Integer>不可见,但Comparator可见(它提供compare(Object, Object))。compare(Object, Object)的实现只需将每个参数强制转换为Integer并调用compare(Integer, Integer),这就是您获得异常的原因。

相关内容

  • 没有找到相关文章

最新更新