Ich habe die folgende Java-Klasse
public class HelloWorld {
public static void main(String []args) {
}
}
Wenn ich diese Datei kompiliere und ein sha256 für die resultierende Klassendatei ausführe, erhalte ich
9c8d09e27ea78319ddb85fcf4f8085aa7762b0ab36dc5ba5fd000dccb63960ff HelloWorld.class
Als nächstes habe ich die Klasse geändert und eine leere Zeile wie folgt hinzugefügt:
public class HelloWorld {
public static void main(String []args) {
}
}
Wieder lief ich einen sha256 auf dem Ausgang und erwartete das gleiche Ergebnis, aber stattdessen bekam ich
11f7ad3ad03eb9e0bb7bfa3b97bbe0f17d31194d8d92cc683cfbd7852e2d189f HelloWorld.class
Ich habe diesen TutorialsPoint-Artikel gelesen dass:
Eine Zeile, die nur Leerzeichen enthält, möglicherweise mit einem Kommentar, wird als Leerzeile bezeichnet, und Java ignoriert sie vollständig.
Meine Frage ist also, da Java leere Zeilen ignoriert, warum unterscheidet sich der kompilierte Bytecode für beide Programme?
Der Unterschied in HelloWorld.class
einem 0x03
Byte wird nämlich durch ein 0x04
Byte ersetzt.
java
compilation
javac
bytecode
KNejad
quelle
quelle
Set
s intern mit Randomisierung verwendet, kann dies bei jedem Lauf zu einer anderen Reihenfolge führen. Es kann auch ein benutzerdefiniertes Attribut hinzugefügt werden, das die Kompilierungszeit enthält. Und so weiter ...Antworten:
Grundsätzlich werden Zeilennummern für das Debuggen beibehalten. Wenn Sie also Ihren Quellcode so ändern, wie Sie es getan haben, beginnt Ihre Methode in einer anderen Zeile und die kompilierte Klasse spiegelt den Unterschied wider.
quelle
end-of-transmission
steht für den ASCII-Code 4 undend-of-text
steht für den ASCII-Code 3-g:none
beim Kompilieren mit dem Flag verglichen (wodurch alle Debugging-Informationen entfernt werden, siehe hier ) und in beiden Szenarien den gleichen Hash erhalten.Sie können die Änderung sehen, indem Sie
javap -v
ausführliche Informationen ausgeben. Wie bei anderen bereits erwähnten wird der Unterschied in Zeilennummern liegen:Genauer gesagt unterscheidet sich die Klassendatei im
LineNumberTable
Abschnitt:quelle
Die Annahme, dass "Java Leerzeilen ignoriert", ist falsch. Hier ist ein Code-Snippet, das sich je nach Anzahl der Leerzeilen vor der Methode unterschiedlich verhält
main
:Wenn vorher keine leeren Zeilen vorhanden sind
main
, wird gedruckt"foo"
, aber mit einer leeren Zeile zuvormain
wird gedruckt"bar"
.Da das Laufzeitverhalten unterschiedlich ist, die
.class
Dateien müssen unterschiedlich sein, unabhängig von irgendwelchen Zeitstempeln oder anderen Metadaten.Dies gilt für jede Sprache, die Zugriff auf die Stapelrahmen mit Zeilennummern hat, nicht nur für Java.
Hinweis: Wenn es mit
-g:none
(ohne Debugging-Informationen) kompiliert wurde , werden die Zeilennummern nicht enthalten, werdengetLineNumber()
immer zurückgegeben-1
und das Programm druckt immer"bar"
, unabhängig von der Anzahl der Zeilenumbrüche.quelle
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
.-1
zu bekommen, war die Verwendung der-g:none
Flagge. Gibt es eine andere Möglichkeit, diese Ausnahme mit normal zu erhaltenjavac
?-g
Option. Es gibt auch-g:vars
und-g:source
was die Erzeugung der verhindertLineNumberTable
.Neben den Details zur Zeilennummer für das Debuggen kann Ihr Manifest auch die Erstellungszeit und das Erstellungsdatum speichern. Dies wird natürlich jedes Mal anders sein, wenn Sie kompilieren.
quelle