У меня есть следующий класс Java
public class HelloWorld {
public static void main(String []args) {
}
}
Когда я компилирую этот файл и запускаю sha256 на полученном файле класса, я получаю
9c8d09e27ea78319ddb85fcf4f8085aa7762b0ab36dc5ba5fd000dccb63960ff HelloWorld.class
Затем я изменил класс и добавил пустую строку следующим образом:
public class HelloWorld {
public static void main(String []args) {
}
}
Я снова запустил sha256 на выходе, ожидая получить тот же результат, но вместо этого я получил
11f7ad3ad03eb9e0bb7bfa3b97bbe0f17d31194d8d92cc683cfbd7852e2d189f HelloWorld.class
Я прочитал в этой статье TutorialsPoint, что:
Строка, содержащая только пробел, возможно, с комментарием, называется пустой строкой, и Java полностью игнорирует ее.
Итак, мой вопрос: поскольку Java игнорирует пустые строки, почему скомпилированный байт-код отличается для обеих программ?
А именно разница в том , что в HelloWorld.class
виде 0x03
байт заменяется на 0x04
байт.
java
compilation
javac
bytecode
KNejad
источник
источник
Set
s с рандомизацией внутри, он может создавать разные порядки при каждом запуске. Он также может добавить пользовательский атрибут, содержащий время компиляции. И так далее ...Ответы:
В основном, номера строк сохраняются для отладки, поэтому, если вы измените свой исходный код так, как вы это сделали, ваш метод начинается с другой строки, и скомпилированный класс отражает разницу.
источник
end-of-transmission
расшифровывается как ASCII-код 4 иend-of-text
обозначает ASCII-код 3-g:none
флаг при компиляции (который удаляет всю отладочную информацию, см. Здесь ), и получил одинаковый хэш в обоих сценариях.Вы можете увидеть изменения, используя
javap -v
которые будут выводить подробную информацию. Как и другие, уже упомянутые, разница будет в номерах строк:Точнее, файл класса отличается
LineNumberTable
разделе:источник
Предположение, что «Java игнорирует пустые строки» неверно. Вот фрагмент кода, который ведет себя по-разному в зависимости от количества пустых строк перед методом
main
:Если до этого не было пустых строк
main
, он печатает"foo"
, но с одной пустой строкой раньшеmain
, он печатает"bar"
.Поскольку поведение во время выполнения отличается,
.class
файлы должны быть разными, независимо от меток времени или других метаданных.Это верно для каждого языка, который имеет доступ к кадрам стека с номерами строк, не только для Java.
Примечание: если он скомпилирован с
-g:none
(без какой-либо информации отладки), то номера строк не будут включены,getLineNumber()
всегда возвращаются-1
, и программа всегда печатает"bar"
, независимо от количества разрывов строк.источник
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
.-1
- использовать-g:none
флаг. Есть ли другой способ получить это исключение, используя обычныеjavac
?-g
возможностью. Есть также-g:vars
и то,-g:source
что мешает генерацииLineNumberTable
.Как и любые детали номера строки для отладки, ваш манифест также может хранить время и дату сборки. Это естественно будет отличаться каждый раз, когда вы компилируете.
источник