为什么 Java 在涉及有界泛型时声称有 2 个声明的方法?

Why does Java claim there's 2 declared methods when bounded generics are involved?

定义如下:

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() return 2 种方法:

有没有办法过滤掉这些?

这是类型擦除的结果。在字节码层面,泛型签名只是方法的附加属性,并不用于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),会找到实现方法,编译器生成一个bridge method具有签名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 方法的擦除结果将与擦除接口方法,因此,在这种情况下不需要桥接方法。