Можно ли скомпилировать код Java 8 для работы на Java 7 JVM?



Java 8 вводит важные новые языковые функции, такие как лямбда-выражения.



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

628   5  

5 ответов:

нет, использование 1.8 функций в исходном коде требует, чтобы вы нацелились на 1.8 VM. Я просто попробовал новый выпуск Java 8 и попытался скомпилировать с -target 1.7 -source 1.8, и компилятор отказывается:

$ javac Test -source 1.8 -target 1.7
javac: source release 1.8 requires target release 1.8

методы по умолчанию требуют таких изменений байт-кода и JVM, что они были бы невозможны сделать на Java 7. Верификатор байт-кода Java 7 и ниже будет отклонять интерфейсы с телами методов (за исключением метода статического инициализатора). Попытка эмулировать методы по умолчанию со статическими методами на стороне вызывающего объекта не приведет к тем же результатам, поскольку методы по умолчанию могут быть переопределены в подклассах. Retrolambda имеет ограниченную поддержку для backporting default методы, но он никогда не может быть полностью перенесен, потому что он действительно требует новых функций JVM.

Lambdas может работать на Java 7 как есть, если необходимые классы API просто будут существовать там. Вызываемая динамическая инструкция существует на Java 7, но было бы возможно реализовать лямбды так, чтобы она генерировала лямбда-классы во время компиляции (ранние сборки JDK 8 делали это таким образом), и в этом случае она будет работать на любой версии Java. (Oracle решила использовать invokedynamic для лямбд в будущем proofing; возможно, однажды JVM будет иметь первоклассные функции, поэтому затем invokedynamic можно изменить, чтобы использовать их вместо создания класса для каждой лямбды, тем самым улучшая производительность.) Что делает Retrolambda, так это то, что он обрабатывает все эти вызываемые динамические инструкции и заменяет их анонимными классами; то же самое, что Java 8 делает во время выполнения, когда lamdba invokedynamic вызывается в первый раз.

Повторяющиеся Аннотации - это просто синтаксический сахар. Они байт-код совместим с предыдущими версиями. В Java 7 вам просто нужно будет реализовать вспомогательные методы (например,getAnnotationsByType), которые скрывают детали реализации аннотации контейнера, которая содержит повторяющиеся аннотации.

насколько я знаю, Примечания существуют только во время компиляции, поэтому они не должны требовать изменений байт-кода, поэтому просто изменение номера версии байт-кода Java 8-скомпилированных классов должно быть достаточно, чтобы сделать они работают на Java 7.

имена параметров метода существуют в байт-коде с Java 7, так что это также совместимо. Вы можете получить доступ к ним, прочитав байт-код метода и посмотрев на имена локальных переменных в отладочной информации метода. Например, Spring Framework делает именно это для реализации @PathVariable, Так что, вероятно, есть метод библиотеки, который вы могли бы вызвать. Потому что абстрактные методы интерфейса не имеют тела метода, эта отладочная информация не существует для методов интерфейса в Java 7 и AFAIK ни на Java 8.

другие новые возможности в основном новые API, улучшения в HotSpot и tooling. Некоторые из новых API доступны в виде сторонних библиотек (например, ThreeTen-Backport и streamsupport).

Summa summarum, методы по умолчанию требуют новых функций JVM, но другие языковые функции этого не делают. необходимо скомпилировать код в Java 8, а затем преобразовать байт-код с помощью Retrolambda в формат Java 5/6/7. Как минимум версия байт-кода должна быть изменена, и javac запрещает -source 1.8 -target 1.7 Так retrotranslator требуется.

насколько я знаю, ни одно из этих изменений в JDK 8 не требовало добавления новых байт-кодов. Часть лямбда-инструментов выполняется с помощью invokeDynamic (которые уже существуют в JDK 7). Таким образом, с точки зрения набора инструкций JVM ничто не должно делать кодовую базу несовместимой. Есть, однако, много связанных с API и улучшений компилятора, которые могли бы сделать код из JDK 8 трудным для компиляции/запуска под предыдущими JDKs (но я не пробовал этого).

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

они подробно объясняют, как вещи инструментируются под капотом. Возможно, вы найдете там ответ на свои вопросы.

Если вы готовы использовать "ретротранслятор", попробуйте отличную Ретроламбу Эско Луонтолы:https://github.com/orfjackal/retrolambda

можно сделать -source 1.7 -target 1.7 затем он будет компилироваться. Но он не будет компилироваться, если у вас есть java 8 конкретные функции, такие как lambdas

Comments

    Ничего не найдено.