Mam następującą klasę Java
public class HelloWorld {
public static void main(String []args) {
}
}
Kiedy kompiluję ten plik i uruchamiam sha256 na wynikowym pliku klasy, otrzymuję
9c8d09e27ea78319ddb85fcf4f8085aa7762b0ab36dc5ba5fd000dccb63960ff HelloWorld.class
Następnie zmodyfikowałem klasę i dodałem pusty wiersz w następujący sposób:
public class HelloWorld {
public static void main(String []args) {
}
}
Znów uruchomiłem sha256 na wyjściu, spodziewając się tego samego rezultatu, ale zamiast tego dostałem
11f7ad3ad03eb9e0bb7bfa3b97bbe0f17d31194d8d92cc683cfbd7852e2d189f HelloWorld.class
Przeczytałem o tym artykule z TutorialsPoint, który:
Linia zawierająca tylko białe znaki, prawdopodobnie z komentarzem, jest znana jako pusta linia, a Java całkowicie ją ignoruje.
Moje pytanie brzmi: skoro Java ignoruje puste wiersze, dlaczego skompilowany kod bajtowy jest inny dla obu programów?
Mianowicie różnica, że HelloWorld.class
w 0x03
bajcie jest zastąpiony 0x04
bajt.
java
compilation
javac
bytecode
KNejad
źródło
źródło
Set
z losową funkcją wewnętrzną, może generować inną kolejność przy każdym uruchomieniu. Może także dodać niestandardowy atrybut zawierający czas kompilacji. I tak dalej…Odpowiedzi:
Zasadniczo numery wierszy są przechowywane w celu debugowania, więc jeśli zmienisz kod źródłowy w ten sam sposób, twoja metoda rozpocznie się od innego wiersza, a skompilowana klasa odzwierciedla różnicę.
źródło
end-of-transmission
oznacza kod ASCII 4 iend-of-text
oznacza kod ASCII 3-g:none
flagi podczas kompilacji (która usuwa wszystkie informacje debugowania, patrz tutaj ) i uzyskałem ten sam skrót w obu scenariuszach.Możesz zobaczyć zmianę za pomocą,
javap -v
która wyświetli pełne informacje. Podobnie jak inne wcześniej wspomniane, różnica będzie podana w numerach wierszy:Dokładniej plik klasy różni się w
LineNumberTable
sekcji:źródło
Założenie, że „Java ignoruje puste linie” jest błędne. Oto fragment kodu, który zachowuje się inaczej w zależności od liczby pustych linii przed metodą
main
:Jeśli wcześniej nie było żadnych pustych linii
main
, drukuje"foo"
, ale z jedną pustą linią wcześniejmain
, drukuje"bar"
.Ponieważ zachowanie w czasie wykonywania jest inne,
.class
pliki muszą być różne, niezależnie od znaczników czasu i innych metadanych.Dotyczy to każdego języka, który ma dostęp do ramek stosu z numerami linii, nie tylko w języku Java.
Uwaga: jeśli jest skompilowany
-g:none
(bez żadnych informacji debugujących), wówczas numery linii nie zostaną uwzględnione,getLineNumber()
zawsze zwraca-1
, a program zawsze drukuje"bar"
, niezależnie od liczby podziałów linii.źródło
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
.-1
było użycie-g:none
flagi. Czy istnieje inny sposób uzyskania tego wyjątku za pomocą zwykłegojavac
?-g
opcją. Jest też-g:vars
i-g:source
który zapobiega generowaniuLineNumberTable
.Oprócz szczegółów numeru linii do debugowania, manifest może także przechowywać datę i godzinę kompilacji. Będzie to naturalnie różnić się przy każdym kompilacji.
źródło