Почему Java утверждает, что есть 2 объявленных метода, когда задействованы ограниченные дженерики?
Со следующими определениями:
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)
Есть ли способ отфильтровать это?
1 ответ
Это является следствием стирания типа. На уровне байтового кода общие сигнатуры являются лишь дополнительным атрибутом методов, не используемых для диспетчеризации методов 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)
, найдет метод реализации, компилятор сгенерирует метод моста, имеющий сигнатуру Object findOne(Object)
и состоящий из простой делегации Object findOne(Serializable)
, выполняя приведение типа в случае необходимости.
Вы можете определить метод моста, вызвав isBridge()
на Method
пример.
Вы также можете использовать знания о том, как работает стирание типов, чтобы повлиять на результат. Изменяя объявление на
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
Метод будет идентичен стиранию метода интерфейса, поэтому в этом случае не потребуется никакого метода моста.