Lassen Sie mich zunächst sagen, dass ich nicht denke, dass die subtilen Unterschiede zwischen Java-Bytecode und MSIL einen unerfahrenen .NET-Entwickler stören sollten. Beide dienen dem gleichen Zweck, eine abstrakte Zielmaschine zu definieren, die eine Schicht über der am Ende verwendeten physischen Maschine ist.
MSIL und Java-Bytecode sind sehr ähnlich. Tatsächlich gibt es ein Tool namens Grasshopper, das MSIL in Java-Bytecode übersetzt. Ich war Teil des Entwicklungsteams für Grasshopper, damit ich ein wenig von meinem (verblassten) Wissen teilen kann. Bitte beachten Sie, dass ich mit der Veröffentlichung von .NET Framework 2.0 aufgehört habe, daran zu arbeiten, sodass einige dieser Dinge möglicherweise nicht mehr zutreffen (wenn ja, hinterlassen Sie bitte einen Kommentar und ich werde ihn korrigieren).
.NET ermöglicht benutzerdefinierte Typen mit Wertesemantik, die der regulären Referenzsemantik ( struct) zugeordnet sind.
.NET unterstützt vorzeichenlose Typen, wodurch der Befehlssatz etwas umfangreicher wird.
Java enthält die Ausnahmespezifikation von Methoden im Bytecode. Obwohl die Ausnahmespezifikation normalerweise nur vom Compiler erzwungen wird, kann sie von der JVM erzwungen werden, wenn ein anderer als der Standardklassenlader verwendet wird.
.NET-Generika werden in IL ausgedrückt, während Java-Generika nur die Typlöschung verwenden .
.NET-Attribute haben in Java keine Entsprechung (stimmt das noch?).
.NET enumssind nicht viel mehr als Wrapper für ganzzahlige Typen, während Javaenums ziemlich vollwertige Klassen sind (danke an Internet Friend für das Kommentieren).
.NET hat outund refParameter.
Es gibt andere Sprachunterschiede, aber die meisten werden nicht auf Bytecode-Ebene ausgedrückt. Wenn beispielsweise der Speicher für Javas nicht- staticinnere Klassen (die in .NET nicht vorhanden sind) keine Bytecode-Funktion darstellt, generiert der Compiler ein zusätzliches Argument für der Konstruktor der inneren Klasse und übergibt das äußere Objekt. Gleiches gilt für .NET-Lambda-Ausdrücke.
In Bezug auf Attribute - Java-Annotationen können so eingestellt werden, dass sie auch im Bytecode erscheinen, sodass es eine Entsprechung gibt.
Eiche
@Oak: Java-Annotationen erlauben nur das Übergeben von Daten, während .NET-Attribute voll leistungsfähige Klassen sind, die möglicherweise über Logik verfügen und vor allem Schnittstellen implementieren.
Fyodor Soikin
Bytecode hat auch separate Rückgabeanweisungen für jede Art von Rückgabetyp, keine Ahnung, ob dies tatsächlich zur Typensicherheit beiträgt.
Cecil Geschirrspüler
1
Die Tatsache, dass Werttypen in .NET manchmal auf dem Stapel zugewiesen werden können, ist im Vergleich zu der Tatsache, dass sie eine Wertsemantik aufweisen , von trivialer Bedeutung . Jeder Wertspeicherort ist eine Instanz. Im Gegensatz dazu ist jeder Speicherort in Java entweder eine primitive oder eine promiskuitive Objektreferenz. Es gibt keine anderen Typen.
Supercat
1
Haben Sie sich gefragt, wie sie die Leistung vergleichen? Ist MSIL schneller zu interpretieren als Bytecode für z.
Luke T O'Brien
23
CIL (der richtige Name für MSIL) und Java-Bytecode sind mehr gleich als verschieden. Es gibt jedoch einige wichtige Unterschiede:
1) CIL wurde von Anfang an als Ziel für mehrere Sprachen entwickelt. Als solches unterstützt es ein viel umfangreicheres Typsystem, einschließlich vorzeichenbehafteter und vorzeichenloser Typen, Werttypen, Zeiger, Eigenschaften, Delegaten, Ereignisse, Generika, eines Objektsystems mit einer einzigen Wurzel und mehr. CIL unterstützt Funktionen, die für die anfänglichen CLR-Sprachen (C # und VB.NET) nicht erforderlich sind, wie globale Funktionen und Tail-Call-Optimierungen . Im Vergleich dazu wurde Java-Bytecode als Ziel für die Java-Sprache entwickelt und spiegelt viele der in Java selbst festgestellten Einschränkungen wider. Es wäre viel schwieriger, C oder Schema mit Java-Bytecode zu schreiben.
2) CIL wurde so konzipiert, dass es sich problemlos in native Bibliotheken und nicht verwalteten Code integrieren lässt
3) Java-Bytecode wurde so konzipiert, dass er entweder interpretiert oder kompiliert werden kann, während CIL nur unter der Annahme einer JIT-Kompilierung entworfen wurde. Bei der ersten Implementierung von Mono wurde jedoch ein Interpreter anstelle einer JIT verwendet.
4) CIL wurde so konzipiert ( und spezifiziert ), dass es ein von Menschen lesbares und beschreibbares Assembler-Formular enthält, das direkt dem Bytecode-Formular zugeordnet ist. Ich glaube, dass Java-Bytecode (wie der Name schon sagt) nur maschinenlesbar sein sollte. Natürlich lässt sich Java-Bytecode relativ leicht wieder in das ursprüngliche Java zurückkompilieren und kann, wie unten gezeigt, auch "zerlegt" werden.
Ich sollte beachten, dass die JVM (die meisten von ihnen) stärker optimiert ist als die CLR (eine von ihnen). Die Rohleistung könnte daher ein Grund sein, lieber auf Java-Bytecode abzuzielen. Dies ist jedoch ein Implementierungsdetail.
Einige Leute sagen, dass der Java-Bytecode für mehrere Plattformen ausgelegt war, während CIL nur für Windows ausgelegt war. Das ist nicht der Fall. Es gibt einige "Windows" -Ismen im .NET-Framework, aber keine in CIL.
Als Beispiel für Punkt 4) oben habe ich vor einiger Zeit ein Spielzeug-Java an den CIL-Compiler geschrieben. Wenn Sie diesem Compiler das folgende Java-Programm geben:
.assembly extern mscorlib { }
.assembly 'Factorial' { .ver 0:0:0:0 }
.class private auto ansi beforefieldinit Factorial extends [mscorlib]System.Object
{
.method publicstaticdefaultvoidmain(string[] a) cil managed
{
.entrypoint
.maxstack 16
newobj instance voidclassFac::'.ctor'()
ldc.i4 3
callvirtinstanceint32classFac::ComputeFac (int32)
callvoidclass [mscorlib]System.Console::WriteLine(int32)
ret
}
}
.classprivateFacextends [mscorlib]System.Object{
.method public instance defaultvoid'.ctor' () cil managed
{
ldarg.0
call instance void object::'.ctor'()
ret
}
.method public int32 ComputeFac(int32 num) cil managed
{
.locals init( int32 num_aux )
ldarg num
ldc.i4 1
clt
brfalse L1
ldc.i4 1
stloc num_aux
br L2
L1:
ldarg num
ldarg.0
ldarg num
ldc.i4 1
sub
callvirt instance int32 class Fac::ComputeFac(int32)
mul
stloc num_aux
L2:
ldloc num_aux
ret
}
}
Dies ist ein gültiges CIL-Programm, das in einen CIL-Assembler eingespeist werden kann ilasm.exe, um eine ausführbare Datei zu erstellen. Wie Sie sehen können, ist CIL eine vollständig von Menschen lesbare und beschreibbare Sprache. Sie können problemlos gültige CIL-Programme in jedem Texteditor erstellen.
Sie können das obige Java-Programm auch mit dem javacCompiler kompilieren und dann die resultierenden Klassendateien über den javap"Disassembler" ausführen , um Folgendes zu erhalten:
Die javapAusgabe ist (meines Wissens) nicht kompilierbar, aber wenn Sie sie mit der obigen CIL-Ausgabe vergleichen, können Sie sehen, dass die beiden sehr ähnlich sind.
Es stellte sich heraus, dass versucht wurde, eine lesbare / beschreibbare Java-Assemblersprache zu erstellen. Zwei, die ich gefunden habe, sind Jasmin und Java Bytecode Assembler
Justin
2
Ich habe hier eine geschrieben, die viel besser ist. Im Gegensatz zu Jasmin ist es so konzipiert, dass es alle gültigen Klassendateien zerlegen und wieder zusammensetzen kann. github.com/Storyyeller/Krakatau . Ich denke, es wäre genauer zu sagen, dass Microsoft einen Standard-Assembler bereitstellt, während Java-Codierer ihre eigenen erstellen müssen.
Antimon
22
Sie machen im Wesentlichen dasselbe, MSIL ist Microsofts Version des Java-Bytecodes.
Die Hauptunterschiede intern sind:
Bytecode wurde sowohl für die Kompilierung als auch für die Interpretation entwickelt, während MSIL explizit für die JIT-Kompilierung entwickelt wurde
MSIL wurde entwickelt, um mehrere Sprachen (C # und VB.NET usw.) zu unterstützen, während Bytecode nur für Java geschrieben wird, was dazu führt, dass Bytecode Java syntaktisch ähnlicher ist als IL einer bestimmten .NET-Sprache
MSIL hat eine explizitere Abgrenzung zwischen Wert- und Referenztypen
Viele weitere Informationen und einen detaillierten Vergleich finden Sie in diesem Artikel von K John Gough (Postscript-Dokument)
"1.Bytecode wurde sowohl für die Kompilierung als auch für die Interpretation entwickelt, während MSIL explizit für die JIT-Kompilierung entwickelt wurde." - Hier geht es darum, wie Java-Code zu Bytecode kompiliert wird UND dieser Bytecode interpretiert wird. Hab ich recht? Wird MSIL nicht zur Ausführung interpretiert?
Abdul
2
CIL aka MSIL soll für Menschen lesbar sein. Java-Bytecode ist nicht.
Stellen Sie sich Java-Bytecode als Maschinencode für Hardware vor, die nicht vorhanden ist (aber von JVMs emuliert wird).
CIL ist eher eine Assemblersprache - ein Schritt vom Maschinencode entfernt und dennoch für den Menschen lesbar.
Bytecode ist eigentlich sehr gut lesbar, solange Sie einen Hex-Editor haben. Es ist eine ziemlich einfache stapelbasierte Sprache mit Erweiterungen zur direkten Darstellung von Klassen und Methoden. Ich dachte, dass MSIL niedriger ist (zB Register)?
Daniel Spiewak
en.wikibooks.org/wiki/… en.wikibooks.org/wiki/… Eines ist das rohe CIL. Der andere ist zerlegter Bytecode. Bytecode ist möglicherweise einigermaßen lesbar, wenn Sie hexadezimal bearbeiten, aber das ist kein Entwurfsziel.
schlank
"Zerlegt" ist wirklich das falsche Wort dafür. Vielleicht "entschlüsselt". Bytecode ist in den .class-Dateien nur aus Gründen der Kompaktheit nicht lesbar. Im Gegensatz zur Manpage von javap ist es nicht erforderlich, lesbaren Bytecode aus einer kompilierten Klasse zu erstellen.
Daniel Spiewak
2
Es gibt nicht so viele Unterschiede. Beide sind Zwischenformate des von Ihnen geschriebenen Codes. Bei der Ausführung führen die virtuellen Maschinen die verwaltete Zwischensprache aus. Dies bedeutet, dass die virtuelle Maschine die Variablen und Aufrufe steuert. Es gibt sogar eine Sprache, an die ich mich momentan nicht erinnere und die auf dieselbe Weise bei .Net und Java ausgeführt werden kann.
Im Grunde ist es nur ein anderes Format für das gleiche
Bearbeiten: Gefunden die Sprache (neben Scala): Es ist FAN ( http://www.fandev.org/ ), sieht sehr interessant aus, aber noch keine Zeit zu bewerten
Scala kann so kompiliert werden, dass es auf die JVM oder die CLR abzielt und Bytecode bzw. MSIL generiert.
Daniel Spiewak
Gut zu wissen, aber ich habe vor ungefähr einem Monat eine andere Sprache gefunden, als ich DZone gelesen habe: Gefunden! Siehe Bearbeiten meines Beitrags
GHad
1
Einverstanden sind die Unterschiede klein genug, um als Anfänger zu arbeiten. Wenn Sie .Net ausgehend von den Grundlagen lernen möchten, empfehlen wir Ihnen, sich die Common Language Infrastructure und das Common Type System anzusehen.
Ich denke, MSIL sollte nicht mit Java-Bytecode verglichen werden, sondern mit "der Anweisung, die die Java-Bytecodes enthält".
Es gibt keinen Namen für den zerlegten Java-Bytecode. "Java Bytecode" sollte ein inoffizieller Alias sein, da ich seinen Namen nicht im offiziellen Dokument finden kann.
Der Java Class File Disassembler sagt
Druckt disassemblierten Code, dh die Anweisungen, die die Java-Bytecodes enthalten, für jede der Methoden in der Klasse aus. Diese sind in der Java Virtual Machine-Spezifikation dokumentiert.
Sowohl "Java VM-Anweisungen" als auch "MSIL" werden zu .NET-Bytecode und Java-Code zusammengesetzt, die nicht von Menschen gelesen werden können.
Antworten:
Lassen Sie mich zunächst sagen, dass ich nicht denke, dass die subtilen Unterschiede zwischen Java-Bytecode und MSIL einen unerfahrenen .NET-Entwickler stören sollten. Beide dienen dem gleichen Zweck, eine abstrakte Zielmaschine zu definieren, die eine Schicht über der am Ende verwendeten physischen Maschine ist.
MSIL und Java-Bytecode sind sehr ähnlich. Tatsächlich gibt es ein Tool namens Grasshopper, das MSIL in Java-Bytecode übersetzt. Ich war Teil des Entwicklungsteams für Grasshopper, damit ich ein wenig von meinem (verblassten) Wissen teilen kann. Bitte beachten Sie, dass ich mit der Veröffentlichung von .NET Framework 2.0 aufgehört habe, daran zu arbeiten, sodass einige dieser Dinge möglicherweise nicht mehr zutreffen (wenn ja, hinterlassen Sie bitte einen Kommentar und ich werde ihn korrigieren).
struct
) zugeordnet sind.enums
sind nicht viel mehr als Wrapper für ganzzahlige Typen, während Javaenums
ziemlich vollwertige Klassen sind (danke an Internet Friend für das Kommentieren).out
undref
Parameter.Es gibt andere Sprachunterschiede, aber die meisten werden nicht auf Bytecode-Ebene ausgedrückt. Wenn beispielsweise der Speicher für Javas nicht-
static
innere Klassen (die in .NET nicht vorhanden sind) keine Bytecode-Funktion darstellt, generiert der Compiler ein zusätzliches Argument für der Konstruktor der inneren Klasse und übergibt das äußere Objekt. Gleiches gilt für .NET-Lambda-Ausdrücke.quelle
CIL (der richtige Name für MSIL) und Java-Bytecode sind mehr gleich als verschieden. Es gibt jedoch einige wichtige Unterschiede:
1) CIL wurde von Anfang an als Ziel für mehrere Sprachen entwickelt. Als solches unterstützt es ein viel umfangreicheres Typsystem, einschließlich vorzeichenbehafteter und vorzeichenloser Typen, Werttypen, Zeiger, Eigenschaften, Delegaten, Ereignisse, Generika, eines Objektsystems mit einer einzigen Wurzel und mehr. CIL unterstützt Funktionen, die für die anfänglichen CLR-Sprachen (C # und VB.NET) nicht erforderlich sind, wie globale Funktionen und Tail-Call-Optimierungen . Im Vergleich dazu wurde Java-Bytecode als Ziel für die Java-Sprache entwickelt und spiegelt viele der in Java selbst festgestellten Einschränkungen wider. Es wäre viel schwieriger, C oder Schema mit Java-Bytecode zu schreiben.
2) CIL wurde so konzipiert, dass es sich problemlos in native Bibliotheken und nicht verwalteten Code integrieren lässt
3) Java-Bytecode wurde so konzipiert, dass er entweder interpretiert oder kompiliert werden kann, während CIL nur unter der Annahme einer JIT-Kompilierung entworfen wurde. Bei der ersten Implementierung von Mono wurde jedoch ein Interpreter anstelle einer JIT verwendet.
4) CIL wurde so konzipiert ( und spezifiziert ), dass es ein von Menschen lesbares und beschreibbares Assembler-Formular enthält, das direkt dem Bytecode-Formular zugeordnet ist. Ich glaube, dass Java-Bytecode (wie der Name schon sagt) nur maschinenlesbar sein sollte. Natürlich lässt sich Java-Bytecode relativ leicht wieder in das ursprüngliche Java zurückkompilieren und kann, wie unten gezeigt, auch "zerlegt" werden.
Ich sollte beachten, dass die JVM (die meisten von ihnen) stärker optimiert ist als die CLR (eine von ihnen). Die Rohleistung könnte daher ein Grund sein, lieber auf Java-Bytecode abzuzielen. Dies ist jedoch ein Implementierungsdetail.
Einige Leute sagen, dass der Java-Bytecode für mehrere Plattformen ausgelegt war, während CIL nur für Windows ausgelegt war. Das ist nicht der Fall. Es gibt einige "Windows" -Ismen im .NET-Framework, aber keine in CIL.
Als Beispiel für Punkt 4) oben habe ich vor einiger Zeit ein Spielzeug-Java an den CIL-Compiler geschrieben. Wenn Sie diesem Compiler das folgende Java-Programm geben:
class Factorial{ public static void main(String[] a){ System.out.println(new Fac().ComputeFac(10)); } } class Fac { public int ComputeFac(int num){ int num_aux ; if (num < 1) num_aux = 1 ; else num_aux = num * (this.ComputeFac(num-1)) ; return num_aux ; } }
Mein Compiler wird die folgende CIL ausspucken:
.assembly extern mscorlib { } .assembly 'Factorial' { .ver 0:0:0:0 } .class private auto ansi beforefieldinit Factorial extends [mscorlib]System.Object { .method public static default void main (string[] a) cil managed { .entrypoint .maxstack 16 newobj instance void class Fac::'.ctor'() ldc.i4 3 callvirt instance int32 class Fac::ComputeFac (int32) call void class [mscorlib]System.Console::WriteLine(int32) ret } } .class private Fac extends [mscorlib]System.Object { .method public instance default void '.ctor' () cil managed { ldarg.0 call instance void object::'.ctor'() ret } .method public int32 ComputeFac(int32 num) cil managed { .locals init ( int32 num_aux ) ldarg num ldc.i4 1 clt brfalse L1 ldc.i4 1 stloc num_aux br L2 L1: ldarg num ldarg.0 ldarg num ldc.i4 1 sub callvirt instance int32 class Fac::ComputeFac (int32) mul stloc num_aux L2: ldloc num_aux ret } }
Dies ist ein gültiges CIL-Programm, das in einen CIL-Assembler eingespeist werden kann
ilasm.exe
, um eine ausführbare Datei zu erstellen. Wie Sie sehen können, ist CIL eine vollständig von Menschen lesbare und beschreibbare Sprache. Sie können problemlos gültige CIL-Programme in jedem Texteditor erstellen.Sie können das obige Java-Programm auch mit dem
javac
Compiler kompilieren und dann die resultierenden Klassendateien über denjavap
"Disassembler" ausführen , um Folgendes zu erhalten:class Factorial extends java.lang.Object{ Factorial(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: new #3; //class Fac 6: dup 7: invokespecial #4; //Method Fac."<init>":()V 10: bipush 10 12: invokevirtual #5; //Method Fac.ComputeFac:(I)I 15: invokevirtual #6; //Method java/io/PrintStream.println:(I)V 18: return } class Fac extends java.lang.Object{ Fac(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return public int ComputeFac(int); Code: 0: iload_1 1: iconst_1 2: if_icmpge 10 5: iconst_1 6: istore_2 7: goto 20 10: iload_1 11: aload_0 12: iload_1 13: iconst_1 14: isub 15: invokevirtual #2; //Method ComputeFac:(I)I 18: imul 19: istore_2 20: iload_2 21: ireturn }
Die
javap
Ausgabe ist (meines Wissens) nicht kompilierbar, aber wenn Sie sie mit der obigen CIL-Ausgabe vergleichen, können Sie sehen, dass die beiden sehr ähnlich sind.quelle
Sie machen im Wesentlichen dasselbe, MSIL ist Microsofts Version des Java-Bytecodes.
Die Hauptunterschiede intern sind:
Viele weitere Informationen und einen detaillierten Vergleich finden Sie in diesem Artikel von K John Gough (Postscript-Dokument)
quelle
CIL aka MSIL soll für Menschen lesbar sein. Java-Bytecode ist nicht.
Stellen Sie sich Java-Bytecode als Maschinencode für Hardware vor, die nicht vorhanden ist (aber von JVMs emuliert wird).
CIL ist eher eine Assemblersprache - ein Schritt vom Maschinencode entfernt und dennoch für den Menschen lesbar.
quelle
Es gibt nicht so viele Unterschiede. Beide sind Zwischenformate des von Ihnen geschriebenen Codes. Bei der Ausführung führen die virtuellen Maschinen die verwaltete Zwischensprache aus. Dies bedeutet, dass die virtuelle Maschine die Variablen und Aufrufe steuert. Es gibt sogar eine Sprache, an die ich mich momentan nicht erinnere und die auf dieselbe Weise bei .Net und Java ausgeführt werden kann.
Im Grunde ist es nur ein anderes Format für das gleiche
Bearbeiten: Gefunden die Sprache (neben Scala): Es ist FAN ( http://www.fandev.org/ ), sieht sehr interessant aus, aber noch keine Zeit zu bewerten
quelle
Einverstanden sind die Unterschiede klein genug, um als Anfänger zu arbeiten. Wenn Sie .Net ausgehend von den Grundlagen lernen möchten, empfehlen wir Ihnen, sich die Common Language Infrastructure und das Common Type System anzusehen.
quelle
Serge Lidin hat ein anständiges Buch über die Details von MSIL: Expert .NET 2.0 IL Assembler verfasst . Ich konnte MSIL auch schnell erlernen, indem ich mir einfache Methoden mit .NET Reflector und Ildasm (Tutorial) ansah .
Die Konzepte zwischen MSIL und Java-Bytecode sind sehr ähnlich.
quelle
Ich denke, MSIL sollte nicht mit Java-Bytecode verglichen werden, sondern mit "der Anweisung, die die Java-Bytecodes enthält".
Es gibt keinen Namen für den zerlegten Java-Bytecode. "Java Bytecode" sollte ein inoffizieller Alias sein, da ich seinen Namen nicht im offiziellen Dokument finden kann. Der Java Class File Disassembler sagt
Sowohl "Java VM-Anweisungen" als auch "MSIL" werden zu .NET-Bytecode und Java-Code zusammengesetzt, die nicht von Menschen gelesen werden können.
quelle