【问题标题】:Why does Java claim there's 2 declared methods when bounded generics are involved?当涉及有界泛型时,为什么 Java 声称有 2 个声明的方法?
【发布时间】:2017-05-22 11:20:10
【问题描述】:

具有以下定义:

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)

有没有办法过滤掉这些?

【问题讨论】:

  • 能否检查Object签名是否标记为桥接方法?
  • @chrylis 是的,确实如此!这解决了我的直接问题。非常感谢!如果您愿意将其扩展为答案,我很乐意投票/接受它。
  • 我不太了解桥接规则,无法写出正确的答案,我只是注意到它符合我收集的模式。

标签: java generics reflection java-bridge-method


【解决方案1】:

这是类型擦除的结果。在字节码层面,泛型签名只是方法的附加属性,不用于 JVM 的方法分派。实际的字节码级别签名源自类型变量绑定的第一种类型,例如对于类型变量 T extends Number&amp;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&amp;Serializable的擦除将是Object,因此,findOne方法的擦除将与接口方法的擦除相同,因此,在这种情况下不需要桥接方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-05
    • 2012-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-16
    相关资源
    最近更新 更多