Почему 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 Метод будет идентичен стиранию метода интерфейса, поэтому в этом случае не потребуется никакого метода моста.

Другие вопросы по тегам