Java为什么会声称存在两个声明的方法当涉及到有界泛型时?

7

以下是相关定义:

public interface BaseService<T, ID> {

    T findOne(ID id);

}

public class BaseServiceImpl<T,ID extends Serializable> implements BaseService<T, ID> {

    @Override
    public T findOne(ID id) {
        return null;
    }

}

为什么BaseServiceImpl.class.getDeclaredMethods()返回2个方法:
  • public java.lang.Object BaseServiceImpl.findOne(java.io.Serializable)
  • public java.lang.Object BaseServiceImpl.findOne(java.lang.Object)
是否有过滤它们的方法?

3
你能否检查一下 Object 签名是否标记为桥接方法? - chrylis -cautiouslyoptimistic-
@chrylis 是的,确实是这样!这解决了我的紧急问题。非常感谢!如果您愿意将其扩展成答案,我很乐意点赞/接受它。 - kaqqao
我对桥牌规则的理解不够深入,无法写出正确的答案,但我注意到它符合我所收集的模式。 - chrylis -cautiouslyoptimistic-
1个回答

5
这是类型擦除的结果。在字节码级别上,泛型签名只是方法的一个附加属性,不用于JVM的方法调用。实际的字节码级别签名是从类型变量绑定的第一个类型派生的,例如对于类型变量 T extends Number&Serializable,原始签名中 T 的替代品将是 Number
针对您的声明,
public interface BaseService<T, ID> {
    T findOne(ID id);
}

TID被替换为Object; 该方法的擦除签名是Object findOne(Object)

对于子类型声明

public class BaseServiceImpl<T,ID extends Serializable> implements BaseService<T, ID> {
    @Override
    public T findOne(ID id) {
        return null;
    }
}
ID extends Serializable的擦除类型是Serializable,这导致实现方法具有擦除签名Object findOne(Serializable)
为了确保使用接口BaseService的代码调用方法Object findOne(Object)能够找到实现方法,编译器生成一个桥接方法,其签名为Object findOne(Object),由一个简单的委托组成,执行Object findOne(Serializable),在必要时进行类型转换。
您可以通过在Method实例上调用isBridge()来识别桥接方法。
您还可以利用类型擦除的工作原理来影响结果。通过更改声明为:
public class BaseServiceImpl<T, ID extends Object&Serializable>
      implements BaseService<T, ID> {
    @Override
    public T findOne(ID id) {
        return null;
    }
}

就通用类型系统而言,没有语义差别,但是 ID extends Object&Serializable 的擦除将会是 Object,因此,findOne 方法的结果擦除将与接口方法的擦除相同,因此,在这种情况下不需要桥接方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接