为什么 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 种方法:
public java.lang.Object BaseServiceImpl.findOne(java.io.Serializable)
public java.lang.Object BaseServiceImpl.findOne(java.lang.Object)
有没有办法过滤掉这些?
这是类型擦除的结果。在字节码层面,泛型签名只是方法的附加属性,并不用于JVM的方法派发。实际的字节码级别签名派生自类型变量绑定的第一种类型,例如对于类型变量 T extends Number&Serializable
,原始签名对 T
的替代将是 Number
.
对于你的声明,
public interface BaseService<T, ID> {
T findOne(ID id);
}
T
和ID
替换为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
方法的擦除结果将与擦除接口方法,因此,在这种情况下不需要桥接方法。
定义如下:
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 种方法:
public java.lang.Object BaseServiceImpl.findOne(java.io.Serializable)
public java.lang.Object BaseServiceImpl.findOne(java.lang.Object)
有没有办法过滤掉这些?
这是类型擦除的结果。在字节码层面,泛型签名只是方法的附加属性,并不用于JVM的方法派发。实际的字节码级别签名派生自类型变量绑定的第一种类型,例如对于类型变量 T extends Number&Serializable
,原始签名对 T
的替代将是 Number
.
对于你的声明,
public interface BaseService<T, ID> {
T findOne(ID id);
}
T
和ID
替换为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
方法的擦除结果将与擦除接口方法,因此,在这种情况下不需要桥接方法。