Ответ 1
токен !
используется ecj для кодирования типа захвата в общих подписях. Следовательно, !*
означает захват неограниченного подстановочного знака.
Внутри ecj использует два варианта CaptureBinding
, один для реализации, что JLS 18.4 вызывает "переменные нового типа", другой для реализации захватывает a la JLS 5.1.10 (в котором используется тот же самый язык "переменных свободного типа" ). Оба создают подпись с помощью !
. При более близком рассмотрении в этом примере у нас есть "старомодный" захват: t
имеет тип capture#1-of ?
, захватывая <T>
в Stream<T>
.
Проблема заключается в следующем: JVMS 4.7.9.1., похоже, не определяет кодировку для таких переменных нового типа (которые среди других свойств не имеют соответствия в исходном коде и, следовательно, нет имени).
Я не смог получить javac
, чтобы испускать любой LocalVariableTypeTable
для лямбда, поэтому они могли бы просто не отвечать на этот вопрос.
Учитывая, что оба компилятора согласны с выводом t
на захват, почему один компилятор генерирует LVTT, а другой нет? JVMS 4.7.14 имеет этот
Эта разница важна только для переменных, тип которых использует переменную типа или параметризованный тип.
В соответствии с JLS, захваты представляют собой переменные типа new, поэтому запись LVTT значительна, и в JVMS отсутствует пропуск, чтобы не указывать формат для этого типа.
Последствия
Приведенное выше описывает и объясняет статус-кво, демонстрируя, что никакая спецификация не говорит компилятору вести себя иначе, чем текущий статус. Очевидно, что это не совсем желательная ситуация.
- Кто-то может обратиться в Oracle, отметив, что Java 8 представляет ситуацию, которая не распространяется на части JVMS. Эта ситуация может стать еще более актуальной, как только локальные переменные станут объектом вывода типа
- Любой, кто наблюдает за негативным воздействием текущей ситуации, приглашается перезвонить в rfe 494198 (ecj), который в противном случае имеет низкий приоритет.
Update: Между тем кто-то сообщил пример, где требуется обычный Signature (который не может быть оппортунически опущен), чтобы кодировать тип, который не может быть закодирован в соответствии с JVMS. В этом случае также javac создает неуказанный байтовый код. Согласно follow-up никакая переменная не должна иметь такого типа, но я не думаю, что это обсуждение завершено (и, по общему признанию, JLS еще не обеспечивает эту цель).
Обновление 2: Получив совет от автора спецификации, я вижу три части в конечном решении:
(1) Каждая подпись типа в любом атрибуте байткода должна придерживаться грамматики в JVMS 4.7.9.1. Ни ecj !
, ни javac <captured wildcard>
не является законным.
(2) Составители должны аппроксимировать сигнатуры типов, где нет юридического кодирования, например, используя стирание вместо захвата. Для записи LVTT такое приближение должно рассматриваться как законное.
(3) JLS должен гарантировать, что только типы, кодируемые с использованием JVMS 4.7.9.1, появляются в позициях, где генерация атрибута Signature является обязательной.
Для будущих версий элементов ecj (1) и (2) были разрешено. Я не могу говорить о графиках, когда javac и JLS будут исправлены соответственно.