Почему класс Java компилируется по-другому с пустой строкой? - PullRequest
0 голосов
/ 03 октября 2018

У меня есть следующий класс 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 байтом.

Ответы [ 4 ]

0 голосов
/ 04 октября 2018

Предположение, что "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", независимо от количества разрывов строки.

0 голосов
/ 03 октября 2018

Вы можете увидеть изменения, используя 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 является необязательным атрибутом переменной длины в таблице атрибутов атрибута Code (§4.7.3).Он может использоваться отладчиками для определения того, какая часть массива кода соответствует данному номеру строки в исходном исходном файле.

Если в таблице атрибутов атрибута Code присутствует несколько атрибутов LineNumberTable, они могутотображаются в любом порядке.

Может быть несколько атрибутов LineNumberTable на строку исходного файла в таблице атрибутов атрибута Code.То есть атрибуты LineNumberTable могут вместе представлять данную строку исходного файла и не должны быть однозначными с исходными строками.

0 голосов
/ 04 октября 2018

Как и любые детали номера строки для отладки, ваш манифест также может хранить время и дату сборки.Это естественно будет отличаться каждый раз, когда вы компилируете.

0 голосов
/ 03 октября 2018

В основном, номера строк сохраняются для отладки, поэтому, если вы измените свой исходный код так, как вы это сделали, ваш метод начинается с другой строки, и скомпилированный класс отражает разницу.

...