Статические методы с одинаковой сигнатурой после стирания типа в Java - PullRequest
0 голосов
/ 15 октября 2019

Это еще один вопрос о методах с сигнатурами, использующими параметризованные типы в Java.

Скажем, у вас есть два следующих метода:

    static void f(List<Integer> l) {}
    static void f(List<String> l) {}

Компилятор будет жаловаться, что оба метода имеют одинаковыесигнатура после стирания типа (оба типа аргументов стираются до List).

Многие похожие вопросы по stackoverflow задают, почему это так, но всегда вопрос касается экземпляров (не статических) методов (см. Метод имеет то же самое стирание, что и другой метод, например, типа .

Обычно половина ответов основана на следующем (очень неправильном) аргументе: компилятор стирает все параметры типа в байт-коде исделать методы неразличимыми. Хорошо, тогда просто напечатайте байт-код с помощью javap, и вы увидите, все ли стерто! (хотя байт-код теряет много данных параметризации, полные сигнатуры методов фактически сохраняются, что, безусловно, полезно, когда вы хотите скомпилировать новый класс, используя зависимость, содержащую общие классы и методы).

С другой сторонылучшие ответы обычно цитируют JLS 8.4.2 и объясняют, что для совместимости со старыми пре-универсальными версиями Java (и необработанными типами в более новых версиях) методы с эквивалентными переопределением сигнатурами запрещены.

IЯ согласен с последним аргументом, за исключением того, что он означает что-то только для методов экземпляра (не статических), поскольку статические методы не могут быть переопределены в любом случае.

Возможно, есть аналогичное объяснение для статических методов, но я не могу точно определить его,Может ли кто-нибудь помочь мне понять это?

1 Ответ

1 голос
/ 15 октября 2019

Аргумент для обратной совместимости остается в силе.

Если у вас был этот код (без использования обобщений, настоятельно не рекомендуется, но допустим даже сегодня, и совершенно нормально в коде Java 1.4, который должен все еще компилироваться)Какой из двух ваших методов должен выбрать компилятор?

List rawList = new ArrayList();
YourClass.f(rawList);

Более конкретно, если предположить, что вы каким-то образом выберете один из двух, в полученном байт-коде сайта вызова, дженерики по-прежнему стираются, поэтому приво время выполнения JVM не знает, какой из двух f(List) вы имели в виду. Вызовы метода указывают имя метода и подпись, но эта подпись не включает обобщенные значения. Это не связано с проблемами совместимости. Могли ли они попытаться продвинуться в этом с чем-то вроде нового кода операции с расширенной спецификацией вызова? Может быть. Но теперь это так.

С другой стороны, лучшие ответы обычно цитируют JLS 8.4.2 и объясняют, что для совместимости со старыми, предопределенными версиями Java (и необработанными типами)в более новых версиях) методы с эквивалентными по переопределению сигнатурами запрещены.

Я согласен с последним аргументом, за исключением того, что он только означает что-то для методов экземпляра (не статических), поскольку статические методы не могут быть переопределены в любом случае.

Ну, вы не можете переопределить статические методы, но ваши два метода по-прежнему "эквивалентны переопределению", то есть они имеют сигнатуру настолько близкую, что вы можете иметь только один из них ввремя (в ситуации с подклассом один переопределит другой, если унаследован из-за этого --- но это также означает, что у вас не может быть двух таких методов в одном классе).

Обратите внимание, что это не создаетлюбые реальные проблемы, поскольку вы всегда можете избежать необходимости «перегрузки», просто изменив имена методов.

...