This is a consequence of type erasure. On the byte code level, generic signatures are only an additional attribute of the methods, not used for the JVM’s method dispatch. The actual byte code level signature is derived from the first type of the type variable’s bound, e.g. for a type variable T extends Number&Serializable
, the raw signature’s substitute for T
would be Number
.
For your declaration,
public interface BaseService<T, ID> {
T findOne(ID id);
}
T
and ID
are substituted with Object
; the method’s erased signature is Object findOne(Object)
.
For the subtype declaration
public class BaseServiceImpl<T,ID extends Serializable> implements BaseService<T, ID> {
@Override
public T findOne(ID id) {
return null;
}
}
the erased type of ID extends Serializable
is Serializable
, which causes the implementation method to have the erased signature Object findOne(Serializable)
.
To ensure that code using the interface BaseService
, calling the method Object findOne(Object)
, will find the implementation method, the compiler generates a bridge method having the signature Object findOne(Object)
and consisting of a plain delegation to Object findOne(Serializable)
, performing type casts where necessary.
You can identify the bridge method by calling isBridge()
on the Method
instance.
You can also use the knowledge of how the type erasure works to influence the result. By changing the declaration to
public class BaseServiceImpl<T, ID extends Object&Serializable>
implements BaseService<T, ID> {
@Override
public T findOne(ID id) {
return null;
}
}
there is no semantic difference regarding the generic type system, but the erasure of ID extends Object&Serializable
will be Object
, hence, the resulting erasure of the findOne
method will be identical to the erasure of the interface method, therefore, no bridge method will be needed in this case.
Object
signature is marked as a bridge method? – Turnkey