Why does Java claim to have 2 declared methods when using limited generics?

With the following definitions:

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; } } 

Why BaseServiceImpl.class.getDeclaredMethods() returns 2 methods:

  • public java.lang.Object BaseServiceImpl.findOne(java.io.Serializable)
  • public java.lang.Object BaseServiceImpl.findOne(java.lang.Object)

Is there any way to filter them out?

+7
java generics reflection
source share
1 answer

This is a consequence of type erasure. At the byte code level, common signatures are just an additional attribute of methods that are not used to send the JVM method. The actual bytecode level signature is inferred from the first type of related type variables, for example. for a variable of type T extends Number&Serializable original signatures will be Number instead of T

For your ad

 public interface BaseService<T, ID> { T findOne(ID id); } 

T and ID replaced by Object ; Object findOne(Object) signature method Object findOne(Object) .

To declare a subtype

 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 means that the implementation method has an erased signature Object findOne(Serializable) .

To make sure that the code using the BaseService interface, by calling the Object findOne(Object) method, finds an implementation method, the compiler generates a bridge method with the signature Object findOne(Object) and consists of a simple delegation to Object findOne(Serializable) , performing type casting if necessary .

You can identify the bridge method by calling isBridge() on the Method instance.

You can also use your knowledge of how type erasure works that affects the result. Changing an ad 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 in the generic type system, but erasing the ID extends Object&Serializable will be Object , therefore, the resulting erasure of the findOne method will be identical to erasing the interface, therefore, in this case no bridge method will be required.

+5
source share

All Articles