Ошибка "оба метода имеют одинаковое стирание" с использованием параметров ограниченного типа

Я впервые использую дженерики в Java и сталкиваюсь с проблемой, которую не могу решить: почему это компилируется:

public interface Aa{}
public interface Bb{}
public interface Cc{}


public static <GenericAB extends Aa & Bb>
void method(GenericAB myABobject1, GenericAB myABobject2){}

public static <GenericAB extends Aa & Bb, GenericCA extends Cc & Aa>
void method(GenericAB myAbobject, GenericCA myCAobject){}

Но это не так:

public interface Aa{}
public interface Bb{}
public interface Cc{}


public static <GenericAB extends Aa & Bb>
void method(GenericAB myABobject1, GenericAB myABobject2){}

public static <GenericAB extends Aa & Bb, GenericAC extends Aa & Cc>
void method(GenericAB myAbobject, GenericAC myACobject){}

И я получаю такую ​​ошибку: оба метода имеют одинаковое стирание.

Прошу прощения, если это глупый вопрос, но я не понимаю, почему порядок интерфейсов в объявлении параметра ограниченного типа кажется имеет значение. На самом деле я не думаю, что причиной ошибки является порядок, но я не понимаю, что именно.

Я читаю эта документация Oracle, он говорит, что я должен указать класс в качестве первого параметра, но Aa, Bb и Cc - все интерфейсы. Извините за мой английский тоже.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
8
0
72
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Важен порядок (§4.6):

The erasure of a type variable (§4.4) is the erasure of its leftmost bound.

GenericBC стирает либо до Aa, либо до Cc, в зависимости от того, что появляется первым (то есть крайним левым) в привязке.

Также см. учебник по стиранию типа и стирание типа, когда и что происходит Вопросы и ответы для объяснения стирания типа в целом.

Спасибо за ответ! Разве это не ограничивает? Или хотя бы сбивает с толку? Я имею в виду, если я хочу перегрузить функцию с помощью дженериков (как я сделал в примере с моим вопросом), почему я должен обращать внимание на порядок? Более того, не рискует ли этот механизм ограничить количество перегруженных методов в зависимости от количества интерфейсов, которые я хочу связать (я не могу прийти к примеру)? Я имею в виду, что если Oracle поступил так, конечно, для этого есть веская причина, но я не понимаю, какая именно. Кстати, завтра я обязательно прочту размещенные вами ссылки, я попытался прочитать их быстро, но они кажутся немного сложными. Спасибо!

Lapo 29.05.2018 20:59

В общем, мы не можем выполнять перегрузки с помощью универсальных шаблонов из-за правила «нет двух методов с одинаковым стиранием». Я собираюсь предположить, что причина, по которой это запрещено, связана с обратной совместимостью (старый код до дженериков с использованием нового пост-дженерикового кода). Я не думаю, что есть какие-то другие ограничения. Я думаю, что есть другие языки JVM, которые допускают такую ​​перегрузку.

Radiodef 29.05.2018 21:49

Хорошо, я читаю ссылки и начинаю понимать, хотя у меня все еще есть некоторые сомнения, но я думаю, что работа с ними - лучший способ к ним привыкнуть. Кстати, когда вы говорите «мы не можем делать перегрузки с помощью дженериков [...]», вы имеете в виду, что мы не должны этого делать или что это невозможно? Я спрашиваю об этом, потому что приведенный выше пример работает, и я перегружаю метод с помощью дженериков. Спасибо!

Lapo 30.05.2018 21:38

Запрещается иметь два метода с одинаковым именем и стиранием. (См. §8.4.8.3 под 1-м полужирным разделом, который начинается как «Это ошибка времени компиляции ...».) Например, void m(List<A> l) {} void m(List<B> l) {} будет ошибкой компилятора, потому что оба метода стирают в void m(List l) {}. Пример в вашем вопросе (где переменные типа стираются по-разному) - это просто довольно неясный частный случай.

Radiodef 30.05.2018 21:46

Потому что во время выполнения после стирания типа оба метода имеют одинаковый заголовок.

public static <GenericAB extends Aa & Bb> void method(GenericAB myABobject1, GenericAB myABobject2){}

становится

public static void method(Aa myABobject1, Aa myABobject2){}

а также

public static <GenericAB extends Aa & Bb, GenericBC extends Aa & Cc>void method(GenericAB myAbobject, GenericBC myBCobject){}

становится

public static void method(Aa myAbobject, Aa myBCobject){}

оба результирующих метода имеют одинаковую подпись, что приводит к вашей ошибке

ИЗМЕНИТЬ после комментариев ниже параметры исправлены

@Radiodef спасибо, я исправил свой пример. Не заметил этого

Michal 29.05.2018 20:25

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