Ich bin neu in .Net und versuche zuerst, die Grundlagen zu verstehen. Was ist der Unterschied zwischen MSIL- und Java-Bytecode?
Ich bin neu in .Net und versuche zuerst, die Grundlagen zu verstehen. Was ist der Unterschied zwischen MSIL- und Java-Bytecode?
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
und ref
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.
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 den javap
"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.
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)
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.
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
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.
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.
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.