При использовании одного и того же JDK (т.е. одного и того же javac
исполняемого файла) всегда ли сгенерированные файлы классов идентичны? Может быть разница в зависимости от операционной системы или оборудования ? Могут ли быть какие-то различия, кроме версии JDK? Есть ли какие-либо параметры компилятора, чтобы избежать различий? Возможно ли различие только в теории или Oracle javac
действительно создает разные файлы классов для одних и тех же входных данных и параметров компилятора?
Обновление 1 Меня интересует генерация , то есть вывод компилятора, а не то, можно ли запускать файл класса на различных платформах.
Обновление 2 Под «Same JDK» я также подразумеваю тот же javac
исполняемый файл.
Обновление 3 Различие между теоретической и практической разницей в компиляторах Oracle.
[РЕДАКТИРОВАТЬ, добавление перефразированного вопроса]
«Каковы обстоятельства, при которых один и тот же исполняемый файл javac при запуске на другой платформе создает другой байт-код?»
источник
Ответы:
Скажем так:
Я могу легко создать полностью совместимый компилятор Java, который никогда не создает один и тот же
.class
файл дважды для одного и того же.java
файла.Я мог бы сделать это, настроив все виды конструкции байт-кода или просто добавив лишние атрибуты в свой метод (что разрешено).
Учитывая, что спецификация не требует, чтобы компилятор создавал файлы классов, идентичные побайтовым, я бы избегал зависимости от такого результата.
Однако несколько раз, которые я проверял, компиляция одного и того же исходного файла с тем же компилятором с теми же переключателями (и теми же библиотеками!) Приводила к одним и тем же
.class
файлам.Обновление: недавно я наткнулся на этот интересный пост в блоге о реализации
switch
onString
в Java 7 . В этом сообщении блога есть некоторые важные части, которые я процитирую здесь (выделено мной):Это довольно ясно иллюстрирует проблему: компилятор не обязан действовать детерминированным образом, если он соответствует спецификации. Разработчики компиляторов, однако, понимать , что это вообще хорошая идея , чтобы попробовать ( при условии , что это не слишком дорого, наверное).
источник
Компиляторы не обязаны создавать один и тот же байт-код на каждой платформе.
javac
Чтобы получить конкретный ответ, вам следует проконсультироваться с утилитами разных поставщиков .Я покажу практический пример этого с упорядочением файлов.
Допустим, у нас есть 2 файла jar:
my1.jar
иMy2.jar
. Они помещаются вlib
каталог рядом. Компилятор читает их в алфавитном порядке (поскольку это такlib
), но в таком порядкеmy1.jar
,My2.jar
когда файловая система нечувствительна к регистру, иMy2.jar
,my1.jar
если она чувствительна к регистру.У
my1.jar
него есть классA.class
с методомMy2.jar
Имеет такое жеA.class
, но с другой сигнатурой методы (принимаетObject
):Понятно, что если вам позвонят
он будет компилировать вызов метода с другой сигнатурой в разных случаях. Итак, в зависимости от чувствительности к регистру вашей файловой системы, в результате вы получите другой класс.
источник
javac
не то же самое, потому что у вас разные двоичные файлы на каждой платформе (например, Win7, Linux, Solaris, Mac). Для поставщика не имеет смысла иметь разные реализации, но любая проблема, связанная с платформой, может повлиять на результат (например, упорядочение полета в каталоге (подумайте о своемlib
каталоге), порядок байтов и т. Д.).javac
них реализована на Java (иjavac
представляет собой простую встроенную программу запуска), поэтому большинство различий платформ не должны иметь никакого влияния.Короткий ответ - НЕТ
Длинный ответ
Они
bytecode
не обязательно должны быть одинаковыми для разных платформ. Это JRE (среда выполнения Java), которая знает, как именно выполнять байт-код.Если вы пройдете через спецификацию Java VM ознакомитесь со вы узнаете, что это не обязательно должно быть правдой, что байт-код одинаков для разных платформ.
Просматривая формат файла класса , он показывает структуру файла класса как
Проверка дополнительной и основной версии
Дополнительная информация в сносках
Итак, исследование всего этого показывает, что файлы классов, созданные на разных платформах, не обязательно должны быть идентичными.
источник
Во-первых, в спецификации такой гарантии нет абсолютно. Соответствующий компилятор может отметить время компиляции в сгенерированном файле класса как дополнительный (настраиваемый) атрибут, и файл класса все равно будет правильным. Однако при каждой сборке он будет создавать разные файлы байтового уровня, и это банально.
Во-вторых, даже без таких неприятных уловок нет причин ожидать, что компилятор будет делать одно и то же дважды подряд, если только его конфигурация и его ввод не идентичны в двух случаях. Спецификация делает описание исходного файла в качестве одного из стандартных атрибутов, и добавление пустых строк в исходном файл также может изменить таблицу номера строки.
В-третьих, я никогда не сталкивался с какими-либо различиями в сборке из-за платформы хоста (кроме той, которая была связана с различиями в том, что было в пути к классам). Код, который может различаться в зависимости от платформы (например, библиотеки собственного кода), не является частью файла класса, и фактическое создание собственного кода из байт-кода происходит после загрузки класса.
В-четвертых (и что наиболее важно) от желания узнать это пахнет дурным запахом процесса (например, запахом кода, но только в отношении того, как вы действуете с кодом). Если возможно, обновляйте исходный код, а не сборку, и, если вам действительно нужно версировать сборку, версию на уровне всего компонента, а не для отдельных файлов классов. Предпочтительно используйте CI-сервер (например, Jenkins) для управления процессом преобразования исходного кода в исполняемый код.
источник
Я считаю, что если вы используете один и тот же JDK, сгенерированный байт-код всегда будет одинаковым, независимо от используемого оборудования и ОС. Создание байтового кода выполняется компилятором java, который использует детерминированный алгоритм для «преобразования» исходного кода в байтовый код. Таким образом, результат всегда будет одинаковым. В этих условиях только обновление исходного кода повлияет на вывод.
источник
В целом, я должен сказать, что нет никакой гарантии, что один и тот же источник будет генерировать один и тот же байт-код при компиляции одним и тем же компилятором, но на другой платформе.
Я бы рассмотрел сценарии с использованием разных языков (кодовых страниц), например Windows с поддержкой японского языка. Подумайте о многобайтовых символах; если компилятор не всегда предполагает, что ему необходимо поддерживать все языки, которые он может оптимизировать для 8-битного ASCII.
В Спецификации языка Java есть раздел о двоичной совместимости .
источник
Java allows you write/compile code on one platform and run on different platform.
AFAIK ; это будет возможно только тогда, когда файл класса, созданный на другой платформе, будет одинаковым или технически одинаковым, т.е. идентичным.редактировать
Под технически одинаковым комментарием я подразумеваю следующее . Они не обязательно должны быть точно такими же, если вы сравниваете побайтово.
Таким образом, согласно спецификации .class-файлу класса на разных платформах не требуется побайтовое сопоставление.
источник
На вопрос:
В пример кросс-компиляции показывает , как мы можем использовать опцию JAVAC: -target версия
Этот флаг генерирует файлы классов, совместимые с версией Java, которую мы указываем при вызове этой команды. Следовательно, файлы классов будут различаться в зависимости от атрибутов, которые мы предоставляем во время сравнения с использованием этой опции.
источник
Скорее всего, ответ - «да», но чтобы получить точный ответ, нужно поискать какие-то ключи или генерацию guid во время компиляции.
Я не могу вспомнить ситуацию, когда это произошло. Например, чтобы иметь идентификатор для сериализации, он жестко запрограммирован, то есть генерируется программистом или IDE.
PS Также может иметь значение JNI.
PPS Я обнаружил, что
javac
само написано на java. Это означает, что он идентичен на разных платформах. Следовательно, он не будет генерировать другой код без причины. Таким образом, он может делать это только с собственными вызовами.источник
Есть два вопроса.
Это теоретический вопрос, и ответ очевиден: да, может быть. Как уже говорили другие, спецификация не требует, чтобы компилятор создавал байтовые идентичные файлы классов.
Даже если каждый существующий компилятор генерирует один и тот же байт-код при любых обстоятельствах (различное оборудование и т. Д.), Завтра ответ может быть другим. Если вы никогда не планируете обновлять javac или свою операционную систему, вы можете протестировать поведение этой версии в ваших конкретных обстоятельствах, но результаты могут быть другими, если вы, например, перейдете от Java 7 Update 11 к Java 7 Update 15.
Это непостижимо.
Я не знаю, является ли управление конфигурацией причиной вашего вопроса, но это вполне понятная причина для беспокойства. Сравнение байт-кодов - это законный контроль ИТ, но только для определения того, изменились ли файлы классов, а не для определения того, изменились ли исходные файлы.
источник
Я бы сказал иначе.
Во-первых, я думаю, что вопрос не в детерминированности:
Конечно, он детерминирован: в информатике трудно добиться случайности, и нет причин, по которым компилятор по какой-либо причине вводит ее здесь.
Во-вторых, если вы переформулируете его следующим образом: «Насколько похожи файлы байт-кода для одного и того же файла исходного кода?», То нет , вы не можете полагаться на тот факт, что они будут похожими .
Хороший способ убедиться в этом - оставить .class (или .pyc в моем случае) на этапе git. Вы поймете, что на разных компьютерах в вашей команде git замечает изменения между файлами .pyc, когда никакие изменения не были внесены в файл .py (и .pyc все равно перекомпилирован).
По крайней мере, я это заметил. Так что поместите * .pyc и * .class в свой .gitignore!
источник