У меня есть приложение Java 8, в котором я скомпилировал байт-код Java 8 с использованием Java 17. Таким образом, source и target являются Java 8. Я сделал это потому, что в Java 17 было много улучшений алгоритмов GC. Я провел небольшое исследование и Я знаю, что мне следует писать в синтаксисе Java 8 (или более ранней версии), если я хочу скомпилировать байт-код Java 8.
Затем я заметил, что не могу использовать функцию Map.of(), так как API помечен @since 9, и это меня смутило. Я не использую новый синтаксис Java. Почему я могу использовать алгоритмы GC, поставляемые с Java 17, но не могу использовать стандартные библиотеки, поставляемые вместе с ним?
Вот как я думаю, это должно работать:
JRE 17 (которая запускает мое приложение) уже содержит все стандартные библиотеки Java 17, скомпилированные в байт-коде Java 17. Поэтому, когда JVM встречает Map.of() (или любые другие методы, отмеченные @since 9+), она должна просто запустить стандартную библиотеку, как обычно.
Кроме того, в чем конкретно проблема с запуском Map.of()?
Но, как я уже сказал, методы уже доступны. Почему нельзя просто использовать их?
Вы явно запросили класс, совместимый с Java 1.8, поэтому javac отказывается компилировать код с Map.of() в нем. Потому что этот файл .class не будет работать с 1.8 JRE.
Потому что, даже если у вас есть JDK 17, вы просите компилятор использовать синтаксис JDK 8. Какая JRE установлена в целевой системе, не имеет значения во время компиляции. Компиляция должна ограничивать использование API JDK 8 и более ранних версий, поскольку вы указали этот источник и цель. Когда на самом деле он развернут в JDK 17, он работает со всеми функциями 17 на уровне JVM, но ваш код по-прежнему скомпилирован с совместимостью с JDK 8. Он также может работать на JRE 8.
На самом деле я ошибся выше. Вы можете использовать javac -source 1.8 -target 1.8 для компиляции кода, использующего Map.of().
Возможно, я ошибаюсь: вы используете инструменты из java17 и синтаксис кода из Java 8. jre из Java8 знает формат из байт-кода, но не имеет реализации для более новых инструментов.
Когда вы говорите: «Я заметил, что не могу использовать функцию Map.of()», что мешало вам ее использовать?
@tgdavies Правда? но ваше объяснение звучит разумно. Если я нацелен на jre 1.8, он должен работать на 1.8, поэтому у него не должно быть Map.of. У меня просто написано "не удается найти символ"
@tgdavies — когда я смотрю исходный код RTL, я не могу найти маркер для методов или классов, который ограничивает этот код определенной версией. Есть только тег @since JavaDoc, и я сомневаюсь, что он будет каким-то образом переведен на что-то вроде if ( version > 1.8 ) или подобное. То, что будут работать чистые расширения классов вроде map.of(), меня не удивляет. Но var не должно работать, также не должно работать сопоставление с образцом при компиляции с -source 1.8. -target 1.8 управляет только бинарным выходом.
В любом случае - вы не хотите этого делать. Ваша «старая Java-программа, которая использует Map.of()», не будет работать на JRE 1.8, потому что она не найдет этот метод, так зачем вообще ориентироваться на 1.8?
Это большой старый проект, который работал на Java 8, мы изменили jre на 17, чтобы использовать алгоритмы GC. Изменение уровня языка до 17 — это еще один шаг, который мы можем сделать в будущем. Поскольку единственными людьми, запускающими нашу программу, являемся мы, я подумал, почему бы не использовать функции в java 17, если мы можем.
Map.of не существует в jdk 1.8, но он действителен. Вы можете нормально скомпилировать исходный/целевой набор для java 1.8. Однако, когда вы пытаетесь запустить его на jvm 1.8, он не может найти метод. Как, по-вашему, этот метод может быть доступен? Кроме того, если вы скомпилируете код, а затем запустите его на jvm 1.8, он будет использовать сборщик мусора 1.8. Как вы думаете, какие проблемы у вас возникнут, если вы измените уровень языка?
@matt Я работаю только на jre 17, который должен найти метод. Мой вопрос заключался в том, как он может использовать GC из java 17, но не Map.of из него?
"он просто говорит "не удается найти символ"" - что это?
(и я до сих пор не понимаю, почему вы не компилируете с исходным кодом и целью 17)
@ParSal Я не верю в это. Если вы используете JRE 8, то он будет использовать этот GC и не сможет найти символ для Map.of, их не существует. Они не включены в файл класса, который вы компилируете. Если вы используете JRE 17, то он будет использовать новый GC и найдет символ для Map.of.
Предположим, я написал инструкции по приготовлению рецепта с двухконфорочной плитой. У вас четырехконфорочная плита. Таким образом, вы можете выполнять несколько шагов одновременно (когда вы используете плиту с четырьмя конфорками), но если вы используете плиту с двумя конфорками, вы не можете. Это печка другая. Не настоящий рецепт. Когда вы запускаете байт-код Java 8 на Java 17 JVM, он может использовать больше устройств записи, он понимает рецепт (ваш байт-код). Чего вы не можете сделать, так это сказать, что этот рецепт предназначен для печи с двумя конфорками, начните с зажигания всех четырех конфорок.
Обновление: я ошибался: как сказал @tgdavies, код компилируется. Виновником в моем случае был <maven.compiler.release> , который делает именно это ! Судя по всему, ответ @matt ниже кажется правильным.
@tgdavies Может ли это внести какие-либо сложности в существующий код? Если у меня есть исходный код java 8, который скомпилирован в java 8 с использованием java 17 и всегда запускается java 17, я не могу придумать ничего, что могло бы пойти не так, если бы я изменил уровень языка на 17.
Верно, "ничего" не могло пойти не так. Если вы компилируете его с помощью jdk 17 с исходным и целевым наборами. Он по-прежнему будет компилироваться без исходного и целевого набора. По сути, объявление источника и цели заставляет jdk 17 работать с подмножеством кода, с которым он работает. Я процитировал «ничего», потому что всегда есть исключение, особенно с аудиторией, которую вы достигаете на SO.




По мере обновления Java меняются некоторые вещи, хотя предполагается, что он останется обратно совместимым. т.е. если вы не используете устаревшие классы, ваш код должен компилироваться и работать с новым jdk.
Байт-код меняется, но вы можете сделать совместимый байт-код, указав javac "нацелить" более старую версию байт-кода.
Кроме того, исходный код меняется. Например, лямбда-выражения. Их не было в java 1.6, поэтому вы не можете их использовать и ожидаете создания байт-кода, совместимого с 1.6. Вы можете указать javac, что хотите скомпилировать только исходный код, совместимый с java 1.6, и вы получите сообщение об ошибке о лямбда-выражениях.
Когда у вас есть совместимый исходный код и совместимый байт-код, у вас возникают проблемы с библиотеками. Это очень просто, скажем, у меня есть библиотека "mylibrary.jar" и класс "MyClass.class". Я могу скомпилировать код, предоставив библиотеку, если вы хотите запустить этот код. Вам все еще нужна библиотека.
Map.of является дополнением к стандартному jdk, поэтому его нет в 1.8 jdk. Все в нем совместимо с java 8, поэтому он проходит исходный и целевой тесты. Вам просто нужно предоставить его при запуске программы. Как и в любой другой библиотеке.
Этот метод не существует в версии 8 Java. Поэтому вы не можете использовать его с версией 8 Java. Предположим, вы построили новый дом. Предположим, что в новом доме есть новая печь. Почему ты не можешь использовать эту печь в своем старом доме? Потому что в новом доме.