Sind bei Verwendung desselben JDK (dh derselben javac
ausführbaren Datei) die generierten Klassendateien immer identisch? Kann es je nach Betriebssystem oder Hardware einen Unterschied geben ? Könnten außer der JDK-Version noch andere Faktoren zu Unterschieden führen? Gibt es Compileroptionen, um Unterschiede zu vermeiden? Ist ein Unterschied nur theoretisch möglich oder erzeugt Oracle javac
tatsächlich unterschiedliche Klassendateien für dieselben Eingabe- und Compileroptionen?
Update 1 Ich habe Interesse an der Erzeugung , dh Compiler - Ausgang, nicht , ob eine Klassendatei werden kann laufen auf verschiedenen Plattformen.
Update 2 Mit "Same JDK" meine ich auch die gleiche javac
ausführbare Datei.
Update 3 Unterscheidung zwischen theoretischem und praktischem Unterschied bei Oracle-Compilern.
[BEARBEITEN, paraphrasierte Frage hinzufügen]
"Unter welchen Umständen erzeugt dieselbe ausführbare Javac-Datei, wenn sie auf einer anderen Plattform ausgeführt wird, einen anderen Bytecode?"
quelle
Antworten:
Sagen wir mal so:
Ich kann leicht einen vollständig konformen Java-Compiler
.class
erstellen, der bei derselben.java
Datei niemals zweimal dieselbe Datei erstellt.Ich könnte dies tun, indem ich alle Arten von Bytecode-Konstruktionen optimiere oder einfach überflüssige Attribute zu meiner Methode hinzufüge (was erlaubt ist).
Da die Spezifikation nicht erfordert, dass der Compiler byteweise identische Klassendateien erstellt, würde ich es vermeiden , von einem solchen Ergebnis abhängig zu sein.
Jedoch , die wenige Male , dass ich überprüft habe, die gleiche Quelldatei mit dem gleichen Compiler mit den gleichen Schaltern (und den gleichen Bibliotheken!) Kompilieren taten Ergebnis in den gleichen
.class
Dateien.Update: Ich bin kürzlich über diesen interessanten Blog-Beitrag über die Implementierung von
switch
onString
in Java 7 gestolpert . In diesem Blog-Beitrag gibt es einige relevante Teile, die ich hier zitieren werde (Hervorhebung von mir):Dies verdeutlicht das Problem ziemlich deutlich: Der Compiler muss nicht deterministisch handeln, solange er der Spezifikation entspricht. Die Compiler-Entwickler erkennen jedoch, dass es im Allgemeinen eine gute Idee ist, es zu versuchen (vorausgesetzt, es ist wahrscheinlich nicht zu teuer).
quelle
Die Compiler sind nicht verpflichtet, auf jeder Plattform denselben Bytecode zu erstellen. Sie sollten das
javac
Dienstprogramm der verschiedenen Anbieter konsultieren , um eine spezifische Antwort zu erhalten.Ich werde ein praktisches Beispiel dafür mit der Reihenfolge der Dateien zeigen.
Nehmen wir an, wir haben 2 JAR-Dateien:
my1.jar
undMy2.jar
. Sie werdenlib
nebeneinander in das Verzeichnis gestellt . Der Compiler liest sie in alphabetischer Reihenfolge (da dieslib
), aber die Reihenfolge istmy1.jar
,My2.jar
wenn das Dateisystem Groß- und Kleinschreibung ist, undMy2.jar
,my1.jar
wenn es Groß- und Kleinschreibung.Der
my1.jar
hat eine KlasseA.class
mit einer MethodeDas
My2.jar
hat das gleicheA.class
, aber mit unterschiedlicher Methodensignatur (akzeptiertObject
):Es ist klar, dass, wenn Sie einen Anruf haben
In verschiedenen Fällen wird ein Methodenaufruf mit unterschiedlicher Signatur kompiliert. Also, je nach Dateisystem Fall Empfindsamkeit, werden Sie andere Klasse als Ergebnis erhalten.
quelle
javac
ist nicht dasselbe, da Sie auf jeder Plattform unterschiedliche Binärdateien haben (z. B. Win7, Linux, Solaris, Mac). Für einen Anbieter ist es nicht sinnvoll, unterschiedliche Implementierungen zu haben, aber jedes plattformspezifische Problem kann das Ergebnis beeinflussen (z. B. Flugreihenfolge in einem Verzeichnis (denken Sie an Ihrlib
Verzeichnis), Endianness usw.).javac
in Java implementiert (undjavac
ist nur ein einfacher nativer Launcher), sodass die meisten Plattformunterschiede keine Auswirkungen haben sollten.Kurze Antwort - NEIN
Lange Antwort
Sie
bytecode
müssen für verschiedene Plattformen nicht gleich sein. Es ist die JRE (Java Runtime Environment), die genau weiß, wie der Bytecode ausgeführt wird.Wenn Sie die Java VM-Spezifikation durchgehen, werden Sie feststellen, dass dies nicht zutreffen muss, da der Bytecode für verschiedene Plattformen gleich ist.
Beim Durchlaufen des Klassendateiformats wird die Struktur einer Klassendatei als angezeigt
Überprüfung der Neben- und Hauptversion
Lesen Sie mehr durch die Fußnoten
Die Untersuchung all dessen zeigt also, dass die auf verschiedenen Plattformen generierten Klassendateien nicht identisch sein müssen.
quelle
Erstens gibt es in der Spezifikation absolut keine solche Garantie. Ein konformer Compiler könnte den Zeitpunkt der Kompilierung als zusätzliches (benutzerdefiniertes) Attribut in die generierte Klassendatei stempeln, und die Klassendatei wäre weiterhin korrekt. Es würde jedoch trivialerweise bei jedem einzelnen Build eine andere Datei auf Byte-Ebene erzeugen.
Zweitens gibt es auch ohne solch böse Tricks keinen Grund zu erwarten, dass ein Compiler zweimal hintereinander genau dasselbe tut, es sei denn, seine Konfiguration und seine Eingabe sind in beiden Fällen identisch. Die Spezifikation macht die Quelle Dateinamen als eine der Standard - Attribute beschreiben, und das Hinzufügen von Leerzeilen zu der Quelldatei und könnte die Zeilennummer Tabelle ändern.
Drittens habe ich aufgrund der Host-Plattform nie einen Unterschied im Build festgestellt (außer dem, der auf Unterschiede im Klassenpfad zurückzuführen war). Der Code, der je nach Plattform variieren würde (dh native Codebibliotheken), ist nicht Teil der Klassendatei, und die eigentliche Generierung von nativem Code aus dem Bytecode erfolgt nach dem Laden der Klasse.
Viertens (und vor allem) stinkt es nach einem schlechten Prozessgeruch (wie ein Codegeruch, aber wie Sie mit dem Code umgehen), um dies wissen zu wollen. Versionieren Sie die Quelle, wenn möglich, nicht den Build, und wenn Sie den Build versionieren müssen, die Version auf der Ebene der gesamten Komponenten und nicht für einzelne Klassendateien. Verwenden Sie vorzugsweise einen CI-Server (z. B. Jenkins), um den Prozess der Umwandlung der Quelle in ausführbaren Code zu verwalten.
quelle
Ich glaube, wenn Sie dasselbe JDK verwenden, wird der generierte Bytecode immer der gleiche sein, ohne Beziehung zu der verwendeten Harware und dem verwendeten Betriebssystem. Die Bytecode-Produktion wird vom Java-Compiler durchgeführt, der einen deterministischen Algorithmus verwendet, um den Quellcode in Bytecode "umzuwandeln". Die Ausgabe bleibt also immer gleich. Unter diesen Bedingungen wirkt sich nur eine Aktualisierung des Quellcodes auf die Ausgabe aus.
quelle
Insgesamt muss ich sagen, dass es keine Garantie dafür gibt, dass dieselbe Quelle denselben Bytecode erzeugt, wenn sie von demselben Compiler kompiliert wird, jedoch auf einer anderen Plattform.
Ich würde Szenarien untersuchen, die verschiedene Sprachen (Codepages) betreffen, zum Beispiel Windows mit japanischer Sprachunterstützung. Denken Sie an Multi-Byte-Zeichen. Sofern der Compiler nicht immer davon ausgeht, dass er alle Sprachen unterstützen muss, wird er möglicherweise für 8-Bit-ASCII optimiert.
In der Java-Sprachspezifikation gibt es einen Abschnitt zur Binärkompatibilität .
quelle
Java allows you write/compile code on one platform and run on different platform.
AFAIK ; Dies ist nur möglich, wenn die auf einer anderen Plattform generierte Klassendatei gleich oder technisch gleich, dh identisch ist.Bearbeiten
Was ich mit technisch gleichem Kommentar meine, ist das. Sie müssen nicht exakt gleich sein, wenn Sie Byte für Byte vergleichen.
Gemäß der Spezifikation muss die .class-Datei einer Klasse auf verschiedenen Plattformen nicht byteweise übereinstimmen.
quelle
Für die Frage:
Das Cross-Compilation-Beispiel zeigt, wie wir die Javac-Option verwenden können: -target version
Dieses Flag generiert Klassendateien, die mit der Java-Version kompatibel sind, die wir beim Aufrufen dieses Befehls angegeben haben. Daher unterscheiden sich die Klassendateien in Abhängigkeit von den Attributen, die wir während der Kompalierung mit dieser Option angeben.
quelle
Höchstwahrscheinlich lautet die Antwort "Ja", aber um eine genaue Antwort zu erhalten, muss beim Kompilieren nach einigen Schlüsseln oder Guid-Generierungen gesucht werden.
Ich kann mich nicht an die Situation erinnern, in der dies geschieht. Um beispielsweise eine ID für Serialisierungszwecke zu haben, ist diese fest codiert, dh sie wird vom Programmierer oder der IDE generiert.
PS Auch JNI kann eine Rolle spielen.
PPS Ich fand, dass
javac
selbst in Java geschrieben ist. Dies bedeutet, dass es auf verschiedenen Plattformen identisch ist. Daher würde es keinen anderen Code ohne Grund generieren. Dies ist also nur bei nativen Anrufen möglich.quelle
Es gibt zwei Fragen.
Dies ist eine theoretische Frage, und die Antwort lautet eindeutig: Ja, das kann es geben. Wie andere gesagt haben, erfordert die Spezifikation nicht, dass der Compiler byteweise identische Klassendateien erzeugt.
Selbst wenn jeder derzeit existierende Compiler unter allen Umständen (unterschiedliche Hardware usw.) denselben Bytecode erzeugt, könnte die Antwort morgen anders sein. Wenn Sie niemals vorhaben, javac oder Ihr Betriebssystem zu aktualisieren, können Sie das Verhalten dieser Version unter Ihren besonderen Umständen testen. Die Ergebnisse können jedoch unterschiedlich sein, wenn Sie beispielsweise von Java 7 Update 11 zu Java 7 Update 15 wechseln.
Das ist nicht zu erkennen.
Ich weiß nicht, ob Konfigurationsmanagement Ihr Grund ist, die Frage zu stellen, aber es ist ein verständlicher Grund, sich darum zu kümmern. Das Vergleichen von Bytecodes ist eine legitime IT-Kontrolle, jedoch nur, um festzustellen, ob sich die Klassendateien geändert haben, und nicht, um festzustellen, ob sich die Quelldateien geändert haben.
quelle
Ich würde es anders ausdrücken.
Erstens denke ich, dass es bei der Frage nicht darum geht, deterministisch zu sein:
Natürlich ist es deterministisch: Zufälligkeit ist in der Informatik schwer zu erreichen, und es gibt keinen Grund, warum ein Compiler sie hier aus irgendeinem Grund einführen würde.
Zweitens, wenn Sie es neu zu formulieren , „wie ähnlich sind Bytecode - Dateien für eine gleiche Sourcecode- Datei?“, Dann Nein , man kann nicht verlassen sich auf die Tatsache , dass sie ähnlich sein wird .
Eine gute Möglichkeit, dies sicherzustellen, besteht darin, die .class (oder in meinem Fall .pyc) in Ihrer Git-Phase zu belassen. Sie werden feststellen, dass git zwischen verschiedenen Computern in Ihrem Team Änderungen zwischen .pyc-Dateien bemerkt, wenn keine Änderungen an der .py-Datei vorgenommen wurden (und .pyc trotzdem neu kompiliert wurde).
Zumindest habe ich das beobachtet. Fügen Sie also * .pyc und * .class in Ihren .gitignore ein!
quelle