Почему класс Java компилируется по-разному с пустой строкой?
у меня есть следующий класс 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 игнорирует пустые строки, почему скомпилированный байтовый код отличается для обеих программ?
а именно разница в классах заключается в том, что в конце-передачи (^D
) символ заменяется символом конца текста (^C
).
4 ответа:
в основном, номера строк сохраняются для отладки, поэтому, если вы измените исходный код так, как вы это сделали, ваш метод начинается с другой строки, и скомпилированный класс отражает разницу.
вы можете увидеть изменения с помощью
javap -v
который выведет подробную информацию. Как и другие уже упомянутые разница будет в номерах строк:$ javap -v HelloWorld.class > with-line.txt $ javap -v HelloWorld.class > no-line.txt $ diff -C 1 no-line.txt with-line.txt *** no-line.txt 2018-10-03 11:43:32.719400000 +0100 --- with-line.txt 2018-10-03 11:43:04.378500000 +0100 *************** *** 2,4 **** Last modified 03-Oct-2018; size 373 bytes ! MD5 checksum 058baea07fb787bdd81c3fb3f9c586bc Compiled from "HelloWorld.java" --- 2,4 ---- Last modified 03-Oct-2018; size 373 bytes ! MD5 checksum 435dbce605c21f84dda48de1a76e961f Compiled from "HelloWorld.java" *************** *** 50,52 **** LineNumberTable: ! line 3: 0 LocalVariableTable: --- 50,52 ---- LineNumberTable: ! line 4: 0 LocalVariableTable:
точнее файл класса отличается в
LineNumberTable
:атрибут LineNumberTable является необязательным атрибутом переменной длины в таблице атрибутов атрибута кода (§4.7.3). Он может использоваться отладчиками для определения того, какая часть массива кода соответствует заданному номеру строки в исходном исходном файле.
Если в таблице атрибутов атрибута кода присутствует несколько атрибутов LineNumberTable, то они могут отображаться в любом порядке.
в таблице атрибутов атрибута кода может быть более одного атрибута LineNumberTable на строку исходного файла. То есть атрибуты LineNumberTable могут вместе представлять заданную строку исходного файла и не должны быть один к одному с исходным файлом русло.
предположение о том, что "Java игнорирует пустые строки" - это неправильно. Вот фрагмент кода, который ведет себя по-разному в зависимости от количества пустых строк перед метод
main
:class NewlineDependent { public static void main(String[] args) { int i = Thread.currentThread().getStackTrace()[1].getLineNumber(); System.out.println((new String[]{"foo", "bar"})[((i % 2) + 2) % 2]); } }
если нет пустых строк перед
main
, он печатает"foo"
, но с одной пустой строкой доmain
, он печатает"bar"
.так как поведение во время выполнения различных,
.class
файлы должны быть разными, независимо от любого метки времени или другие метаданные.это справедливо для каждого языка, который имеет доступ к кадрам стека с номерами строк, а не только для Java.
Примечание: если он собран с
-g:none
(без отладочной информации), то номера строк не будут включены,getLineNumber()
всегда возвращает-1
, и программа всегда выводит"bar"
, независимо от количества строк.