Po pierwsze, pozwólcie mi powiedzieć, że nie sądzę, aby subtelne różnice między kodem bajtowym Javy a MSIL były czymś, co powinno przeszkadzać początkującym programistom .NET. Oba służą temu samemu celowi, definiując abstrakcyjną maszynę docelową, która jest warstwą nad maszyną fizyczną używaną na końcu.
Kod bajtowy MSIL i Java są bardzo podobne, w rzeczywistości istnieje narzędzie o nazwie Grasshopper, które tłumaczy MSIL na kod bajtowy Java. Byłem częścią zespołu programistów Grasshopper, więc mogę podzielić się odrobiną mojej (wyblakłej) wiedzy. Zwróć uwagę, że przestałem nad tym pracować, gdy pojawił się .NET framework 2.0, więc niektóre z tych rzeczy mogą już nie być prawdziwe (jeśli tak, zostaw komentarz, a ja go poprawię).
NET zezwala na typy zdefiniowane przez użytkownika, które mają semantykę wartości dołączoną do zwykłej semantyki odwołań ( struct).
.NET obsługuje typy bez znaku, dzięki czemu zestaw instrukcji jest nieco bogatszy.
Java zawiera specyfikację wyjątków metod w kodzie bajtowym. Chociaż specyfikacja wyjątku jest zwykle wymuszana tylko przez kompilator, może zostać wymuszona przez maszynę JVM, jeśli używany jest inny program ładujący klasy niż domyślny.
.NET typy generyczne są wyrażane w IL, podczas gdy typy generyczne Java używają tylko wymazywania typów .
Atrybuty .NET nie mają odpowiednika w Javie (czy to nadal prawda?).
.NET enumsto niewiele więcej niż otoki wokół typów całkowitych, podczas gdy Javaenums to prawie pełnoprawne klasy (dzięki Internet Friendowi za komentarz).
.NET ma outi refparametry.
Istnieją inne różnice językowe, ale większość z nich nie jest wyrażona na poziomie kodu bajtowego, na przykład, jeśli pamięć obsługuje nie staticwewnętrzne klasy Javy (które nie istnieją w .NET) nie są funkcją kodu bajtowego, kompilator generuje dodatkowy argument do konstruktor klasy wewnętrznej i przekazuje obiekt zewnętrzny. To samo dotyczy wyrażeń lambda .NET.
Odnośnie atrybutów - adnotacje Java można ustawić tak, aby pojawiały się również w kodzie bajtowym, więc istnieje odpowiednik.
Dąb
@ Dąb: adnotacje Java pozwalają tylko na przekazywanie danych, podczas gdy atrybuty .NET są klasami w pełni zasilanymi, które mogą mieć logikę i, co najważniejsze, implementować interfejsy.
Fyodor Soikin
Kod bajtowy ma również oddzielne instrukcje powrotu dla każdego typu zwrotu, nie wiem, czy faktycznie pomaga w bezpieczeństwie typów.
Zmywarka Cecil
1
Fakt, że typy wartości w .NET mogą być czasami przydzielane na stosie, ma trywialne znaczenie w porównaniu z faktem, że mają semantykę wartości ; każda lokalizacja pamięci typu wartościowego jest instancją. Z kolei każda lokalizacja pamięci w Javie jest albo prymitywnym, albo rozwiązłym odniesieniem do obiektu; nie ma innych typów.
supercat
1
Zastanawiałeś się, jak porównują wydajność? Czy MSIL jest szybszy do interpretacji niż kod bajtowy np.?
Luke T. O'Brien
23
CIL (właściwa nazwa dla MSIL) i kod bajtowy Java są bardziej takie same niż różne. Jest jednak kilka ważnych różnic:
1) CIL został zaprojektowany od początku, aby służyć jako cel dla wielu języków. W związku z tym obsługuje znacznie bogatszy system typów, w tym typy podpisane i niepodpisane, typy wartości, wskaźniki, właściwości, delegatów, zdarzenia, typy ogólne, system obiektowy z jednym korzeniem i więcej. CIL obsługuje funkcje, które nie są wymagane dla początkowych języków CLR (C # i VB.NET), takie jak funkcje globalne i optymalizacje wywołań końcowych . Dla porównania, kod bajtowy Java został zaprojektowany jako cel dla języka Java i odzwierciedla wiele ograniczeń występujących w samej Javie. Byłoby znacznie trudniej napisać C lub Scheme przy użyciu kodu bajtowego Java.
2) CIL został zaprojektowany w celu łatwej integracji z natywnymi bibliotekami i niezarządzanym kodem
3) Kod bajtowy Java został zaprojektowany do interpretacji lub kompilacji, podczas gdy CIL został zaprojektowany z założeniem tylko kompilacji JIT. To powiedziawszy, początkowa implementacja Mono wykorzystywała interpreter zamiast JIT.
4) CIL został zaprojektowany ( i określony ) tak, aby miał czytelną dla człowieka i zapisywalną formę języka asemblera, która jest odwzorowywana bezpośrednio na postać kodu bajtowego. Uważam, że kod bajtowy Java (jak sama nazwa wskazuje) miał być przeznaczony tylko do odczytu maszynowego. Oczywiście kod bajtowy Javy jest stosunkowo łatwo dekompilowany z powrotem do oryginalnej Javy i, jak pokazano poniżej, można go również „zdemontować”.
Powinienem zauważyć, że JVM (większość z nich) jest bardziej zoptymalizowany niż CLR (którykolwiek z nich). Tak więc nieprzetworzona wydajność może być powodem, aby preferować celowanie w kod bajtowy Java. Jest to jednak szczegół implementacji.
Niektórzy mówią, że kod bajtowy Javy został zaprojektowany jako wieloplatformowy, podczas gdy CIL został zaprojektowany tylko dla systemu Windows. Nie o to chodzi. W środowisku .NET jest kilka izmów „Windows”, ale nie ma ich w CIL.
Jako przykład punktu 4) powyżej, jakiś czas temu napisałem zabawkową Javę do kompilatora CIL. Jeśli zasilasz ten kompilator następującym programem Java:
.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
}
}
Jest to poprawny program CIL, który można wprowadzić do asemblera CIL, tak jak w ilasm.execelu utworzenia pliku wykonywalnego. Jak widać, CIL jest językiem w pełni czytelnym i zapisywalnym przez człowieka. Możesz łatwo tworzyć prawidłowe programy CIL w dowolnym edytorze tekstu.
Możesz również skompilować powyższy program Java za pomocą javackompilatora, a następnie uruchomić wynikowe pliki klas za pomocą javap„dezasemblera”, aby uzyskać następujące informacje:
Okazuje się, że były próby stworzenia czytelnego / zapisywalnego języka asemblera Java. Dwa, które znalazłem, to Jasmin i Java Bytecode Assembler
Justin
2
Napisałem tutaj jeden, który jest znacznie lepszy. W przeciwieństwie do Jasmin, jest przeznaczony do demontażu i ponownego złożenia dowolnego prawidłowego pliku klasowego. github.com/Storyyeller/Krakatau . Myślę, że dokładniejsze byłoby stwierdzenie, że Microsoft dostarcza standardowy asembler, podczas gdy programiści Java muszą tworzyć własne.
Antymon
22
Zasadniczo robią to samo, MSIL to wersja kodu bajtowego Java firmy Microsoft.
Główne różnice wewnętrzne to:
Kod bajtowy został opracowany zarówno do kompilacji, jak i interpretacji, podczas gdy MSIL został opracowany bezpośrednio do kompilacji JIT
MSIL został opracowany w celu obsługi wielu języków (C # i VB.NET itp.) W porównaniu z kodem bajtowym napisanym tylko dla języka Java, w wyniku czego kod bajtowy jest bardziej podobny składniowo do języka Java niż IL do dowolnego konkretnego języka .NET
MSIL ma bardziej wyraźne rozgraniczenie między typami wartości i odwołań
O wiele więcej informacji i szczegółowe porównanie można znaleźć w artykule K John Gough (dokument postscriptowy)
„1.Kod bajtowy został opracowany zarówno do kompilacji, jak i do interpretacji, podczas gdy MSIL został opracowany specjalnie do kompilacji JIT” - To mówi o tym, jak kod Java jest kompilowany do kodu bajtowego ORAZ ten kod bajtowy jest interpretowany. Mam rację? Czy MSIL nie jest interpretowany w celu wykonania?
Abdul
2
CIL aka MSIL ma być czytelny dla człowieka. Kod bajtowy Java nie jest.
Pomyśl o kodzie bajtowym Java jako o kodzie maszynowym sprzętu, który nie istnieje (ale który emuluje maszyny JVM).
CIL jest bardziej podobny do języka asemblera - jeden krok od kodu maszynowego, a jednocześnie jest czytelny dla człowieka.
Kod bajtowy jest w rzeczywistości bardzo czytelny, o ile masz edytor szesnastkowy. Jest to dość prosty język oparty na stosie z rozszerzeniami do bezpośredniej reprezentacji klas i metod. Myślałem, że MSIL był niższego poziomu (np. Rejestry)?
„Zdemontowany” to naprawdę niewłaściwe określenie. Może „zdekodowane”. Kod bajtowy jest nieczytelny w plikach .class tylko ze względu na zwartość. W przeciwieństwie do strony podręcznika javap, nie ma dezasemblacji związanej z tworzeniem czytelnego kodu bajtowego ze skompilowanej klasy.
Daniel Spiewak
2
Nie ma tak dużych różnic. Oba są formatami pośrednimi napisanego przez Ciebie kodu. Po uruchomieniu maszyny wirtualne będą wykonywać zarządzany język pośredni, co oznacza, że maszyna wirtualna kontroluje zmienne i wywołania. Jest nawet język, którego w tej chwili nie pamiętam, który może działać na .Net i Javie w ten sam sposób.
Zasadniczo jest to po prostu inny format tego samego
Edycja: Znalazłem język (oprócz Scali): To FAN ( http://www.fandev.org/ ), wygląda bardzo interesująco, ale nie ma jeszcze czasu na ocenę
Scala może zostać skompilowana tak, aby była przeznaczona dla JVM lub CLR, generując odpowiednio kod bajtowy lub MSIL.
Daniel Śpiewak
Dobrze wiedzieć, ale jakiś miesiąc temu znalazłem inny język, czytając DZone: Znalazłem go! Zobacz edycję mojego postu
GHad
1
Zgoda, różnice są na tyle niewielkie, że można je przyjąć jako początkujący. Jeśli chcesz nauczyć się .Net zaczynając od podstaw, polecam przyjrzenie się Common Language Infrastructure i Common Type System.
Myślę, że MSIL nie powinien być porównywany z kodem bajtowym Javy, ale „instrukcją zawierającą kody bajtowe Javy”.
Nie ma nazwy zdemontowanego kodu bajtowego Java. „Kod bajtowy Java” powinien być nieoficjalnym aliasem, ponieważ nie mogę znaleźć jego nazwy w oficjalnym dokumencie.
Mówi dezasembler klas Java
Wyświetla zdezasemblowany kod, tj. Instrukcje zawierające kody bajtowe języka Java, dla każdej metody w klasie. Są one udokumentowane w specyfikacji wirtualnej maszyny języka Java.
Zarówno „Instrukcje Java VM”, jak i „MSIL” są składane w kodzie bajtowym .NET i kodzie Java, które nie są czytelne dla człowieka.
Odpowiedzi:
Po pierwsze, pozwólcie mi powiedzieć, że nie sądzę, aby subtelne różnice między kodem bajtowym Javy a MSIL były czymś, co powinno przeszkadzać początkującym programistom .NET. Oba służą temu samemu celowi, definiując abstrakcyjną maszynę docelową, która jest warstwą nad maszyną fizyczną używaną na końcu.
Kod bajtowy MSIL i Java są bardzo podobne, w rzeczywistości istnieje narzędzie o nazwie Grasshopper, które tłumaczy MSIL na kod bajtowy Java. Byłem częścią zespołu programistów Grasshopper, więc mogę podzielić się odrobiną mojej (wyblakłej) wiedzy. Zwróć uwagę, że przestałem nad tym pracować, gdy pojawił się .NET framework 2.0, więc niektóre z tych rzeczy mogą już nie być prawdziwe (jeśli tak, zostaw komentarz, a ja go poprawię).
struct
).enums
to niewiele więcej niż otoki wokół typów całkowitych, podczas gdy Javaenums
to prawie pełnoprawne klasy (dzięki Internet Friendowi za komentarz).out
iref
parametry.Istnieją inne różnice językowe, ale większość z nich nie jest wyrażona na poziomie kodu bajtowego, na przykład, jeśli pamięć obsługuje nie
static
wewnętrzne klasy Javy (które nie istnieją w .NET) nie są funkcją kodu bajtowego, kompilator generuje dodatkowy argument do konstruktor klasy wewnętrznej i przekazuje obiekt zewnętrzny. To samo dotyczy wyrażeń lambda .NET.źródło
CIL (właściwa nazwa dla MSIL) i kod bajtowy Java są bardziej takie same niż różne. Jest jednak kilka ważnych różnic:
1) CIL został zaprojektowany od początku, aby służyć jako cel dla wielu języków. W związku z tym obsługuje znacznie bogatszy system typów, w tym typy podpisane i niepodpisane, typy wartości, wskaźniki, właściwości, delegatów, zdarzenia, typy ogólne, system obiektowy z jednym korzeniem i więcej. CIL obsługuje funkcje, które nie są wymagane dla początkowych języków CLR (C # i VB.NET), takie jak funkcje globalne i optymalizacje wywołań końcowych . Dla porównania, kod bajtowy Java został zaprojektowany jako cel dla języka Java i odzwierciedla wiele ograniczeń występujących w samej Javie. Byłoby znacznie trudniej napisać C lub Scheme przy użyciu kodu bajtowego Java.
2) CIL został zaprojektowany w celu łatwej integracji z natywnymi bibliotekami i niezarządzanym kodem
3) Kod bajtowy Java został zaprojektowany do interpretacji lub kompilacji, podczas gdy CIL został zaprojektowany z założeniem tylko kompilacji JIT. To powiedziawszy, początkowa implementacja Mono wykorzystywała interpreter zamiast JIT.
4) CIL został zaprojektowany ( i określony ) tak, aby miał czytelną dla człowieka i zapisywalną formę języka asemblera, która jest odwzorowywana bezpośrednio na postać kodu bajtowego. Uważam, że kod bajtowy Java (jak sama nazwa wskazuje) miał być przeznaczony tylko do odczytu maszynowego. Oczywiście kod bajtowy Javy jest stosunkowo łatwo dekompilowany z powrotem do oryginalnej Javy i, jak pokazano poniżej, można go również „zdemontować”.
Powinienem zauważyć, że JVM (większość z nich) jest bardziej zoptymalizowany niż CLR (którykolwiek z nich). Tak więc nieprzetworzona wydajność może być powodem, aby preferować celowanie w kod bajtowy Java. Jest to jednak szczegół implementacji.
Niektórzy mówią, że kod bajtowy Javy został zaprojektowany jako wieloplatformowy, podczas gdy CIL został zaprojektowany tylko dla systemu Windows. Nie o to chodzi. W środowisku .NET jest kilka izmów „Windows”, ale nie ma ich w CIL.
Jako przykład punktu 4) powyżej, jakiś czas temu napisałem zabawkową Javę do kompilatora CIL. Jeśli zasilasz ten kompilator następującym programem Java:
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 ; } }
mój kompilator wypluje następujący CIL:
.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 } }
Jest to poprawny program CIL, który można wprowadzić do asemblera CIL, tak jak w
ilasm.exe
celu utworzenia pliku wykonywalnego. Jak widać, CIL jest językiem w pełni czytelnym i zapisywalnym przez człowieka. Możesz łatwo tworzyć prawidłowe programy CIL w dowolnym edytorze tekstu.Możesz również skompilować powyższy program Java za pomocą
javac
kompilatora, a następnie uruchomić wynikowe pliki klas za pomocąjavap
„dezasemblera”, aby uzyskać następujące informacje: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 }
Wynik
javap
nie jest kompilowalny (o ile mi wiadomo), ale jeśli porównasz go z powyższym wynikiem CIL, zobaczysz, że są one bardzo podobne.źródło
Zasadniczo robią to samo, MSIL to wersja kodu bajtowego Java firmy Microsoft.
Główne różnice wewnętrzne to:
O wiele więcej informacji i szczegółowe porównanie można znaleźć w artykule K John Gough (dokument postscriptowy)
źródło
CIL aka MSIL ma być czytelny dla człowieka. Kod bajtowy Java nie jest.
Pomyśl o kodzie bajtowym Java jako o kodzie maszynowym sprzętu, który nie istnieje (ale który emuluje maszyny JVM).
CIL jest bardziej podobny do języka asemblera - jeden krok od kodu maszynowego, a jednocześnie jest czytelny dla człowieka.
źródło
Nie ma tak dużych różnic. Oba są formatami pośrednimi napisanego przez Ciebie kodu. Po uruchomieniu maszyny wirtualne będą wykonywać zarządzany język pośredni, co oznacza, że maszyna wirtualna kontroluje zmienne i wywołania. Jest nawet język, którego w tej chwili nie pamiętam, który może działać na .Net i Javie w ten sam sposób.
Zasadniczo jest to po prostu inny format tego samego
Edycja: Znalazłem język (oprócz Scali): To FAN ( http://www.fandev.org/ ), wygląda bardzo interesująco, ale nie ma jeszcze czasu na ocenę
źródło
Zgoda, różnice są na tyle niewielkie, że można je przyjąć jako początkujący. Jeśli chcesz nauczyć się .Net zaczynając od podstaw, polecam przyjrzenie się Common Language Infrastructure i Common Type System.
źródło
Serge Lidin jest autorem porządnej książki o szczegółach MSIL: Expert .NET 2.0 IL Assembler . Mogłem również szybko przyswoić MSIL, patrząc na proste metody przy użyciu .NET Reflector i Ildasm (samouczek) .
Koncepcje między kodami bajtowymi MSIL i kodem bajtowym Java są bardzo podobne.
źródło
Myślę, że MSIL nie powinien być porównywany z kodem bajtowym Javy, ale „instrukcją zawierającą kody bajtowe Javy”.
Nie ma nazwy zdemontowanego kodu bajtowego Java. „Kod bajtowy Java” powinien być nieoficjalnym aliasem, ponieważ nie mogę znaleźć jego nazwy w oficjalnym dokumencie. Mówi dezasembler klas Java
Zarówno „Instrukcje Java VM”, jak i „MSIL” są składane w kodzie bajtowym .NET i kodzie Java, które nie są czytelne dla człowieka.
źródło