我是.Net的新手,我想先了解基础知识.MSIL和Java字节码有什么区别?
首先请允许我说,我不认为Java字节码和MSIL之间的细微差别应该是新手.NET开发人员的烦恼.它们都用于定义抽象目标机器的相同目的,该机器是最终使用的物理机器之上的层.
MSIL和Java字节码非常相似,实际上有一个名为Grasshopper的工具可以将MSIL转换为Java字节码,我是Grasshopper开发团队的一员,因此我可以分享一些我的(褪色)知识.请注意,当.NET framework 2.0问世时,我已经停止了这方面的工作,因此其中一些事情可能不再适用(如果是这样,请发表评论,我会更正).
.NET允许用户定义的类型具有与常规引用语义(struct
)相关的值语义.
.NET支持无符号类型,这使得指令集更加丰富.
Java包含字节码中方法的异常规范.虽然异常规范通常仅由编译器强制执行,但如果使用非默认类加载器,则JVM可以强制执行异常规范.
.NET泛型用IL表示,而Java泛型仅使用类型擦除.
.NET属性在Java中没有等价物(这仍然是真的吗?).
.NET enums
不仅仅是整数类型的包装器,而Javaenums
几乎是完全成熟的类(感谢Internet Friend的评论).
.NET有out
和ref
参数.
还有其他语言差异,但大部分都没有在字节代码级别表达,例如,如果内存服务于Java的非static
内部类(.NET中不存在)不是字节码功能,则编译器会生成一个额外的参数内部类的构造函数并传递外部对象..NET lambda表达式也是如此.
它们本质上是做同样的事情,MSIL是微软的Java字节码版本.
内部的主要区别是:
字节码是为编译和解释而开发的,而MSIL则是为JIT编译而开发的
MSIL的开发是为了支持多种语言(C#和VB.NET等)而不是只为Java编写的Bytecode,导致Bytecode在语法上比任何特定的.NET语言更类似于Java.
MSIL在值和引用类型之间有更明确的描述
K John Gough在本文中可以找到更多的信息和详细的比较(后记文件)
CIL(MSIL的正确名称)和Java字节码比它们不同的更相同.但是有一些重要的区别:
1)CIL从一开始就被设计为多语言的目标.因此,它支持更丰富的类型系统,包括有符号和无符号类型,值类型,指针,属性,委托,事件,泛型,具有单个根的对象系统等.CIL支持初始CLR语言(C#和VB.NET)不需要的功能,例如全局函数和尾调用优化.相比之下,Java字节码被设计为Java语言的目标,并反映了Java本身的许多约束.使用Java字节码编写C或Scheme会困难得多.
2)CIL旨在轻松集成到本机库和非托管代码中
3)Java字节码被设计为解释或编译,而CIL的设计仅假设JIT编译.也就是说,Mono的初始实现使用了解释器而不是JIT.
4)CIL被设计(并指定)为具有人类可读和可写的汇编语言形式,其直接映射到字节码形式.我相信Java字节码(顾名思义)只是机器可读的.当然,Java字节码相对容易反编译回原始Java,如下所示,它也可以"反汇编".
我应该注意到JVM(大多数)比CLR(其中任何一个)都更加优化.因此,原始性能可能是更喜欢使用Java字节码的原因.这是一个实现细节.
有人说Java字节码设计为多平台,而CIL只设计为Windows.不是这种情况..NET框架中有一些"Windows"主义,但CIL中没有.
作为上面第4点的一个例子,我曾经写过一个玩具Java到CIL编译器.如果您为此编译器提供以下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 ; } }
我的编译器将吐出以下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 } }
这是一个有效的CIL程序,可以输入CIL汇编程序,就像ilasm.exe
创建一个可执行文件.如您所见,CIL是一种完全人类可读写的语言.您可以在任何文本编辑器中轻松创建有效的CIL程序.
您还可以使用编译javac
器编译上面的Java程序,然后通过javap
"反汇编程序" 运行生成的类文件以获取以下内容:
class Factorial extends java.lang.Object{ Factorial(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()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." ":()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." ":()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 }
该javap
输出不编译(据我所知),但如果你把它比作CIL输出上面可以看到两个非常相似.