关于.net:MSIL和Java字节码之间的区别?

关于.net:MSIL和Java字节码之间的区别?

Differences between MSIL and Java bytecode?

我是.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仅仅是整数类型的包装器,而Java enums则是完全成熟的类(感谢Internet Friend的评论)。
  • .NET具有outref参数。

还有其他语言差异,但大多数差异不是在字节码级别表达的,例如,如果内存服务于Java的非static内部类(.NET中不存在)不是字节码功能,则编译器会生成一个内部类的构造函数的附加参数,并传递外部对象。 .NET lambda表达式也是如此。


他们本质上是在做同样的事情,MSIL是Microsoft的Java字节码版本。

内部的主要区别是:

  • 字节码是为编译和解释开发的,而MSIL是为JIT编译明确开发的
  • MSIL的开发是为了支持多种语言(C#和VB.NET等),而字节码仅是为Java编写的,导致字节码在语法上比Java更像Java,而IL在任何特定的.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程序:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    .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程序,可以将其输入到像ilasm.exe这样的CIL汇编程序中以创建可执行文件。如您所见,CIL是一种完全人类可读和可写的语言。您可以在任何文本编辑器中轻松创建有效的CIL程序。

    您还可以使用javac编译器编译上述Java程序,然后通过javap"反汇编程序"运行生成的类文件以获取以下信息:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    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
    }

    javap输出是不可编译的(据我所知),但是如果将其与上面的CIL输出进行比较,您会发现两者非常相似。


    CIL(又称MSIL)旨在为人类可读。 Java字节码不是。

    可以将Java字节码看作是不存在的硬件(但可以模拟JVM)的机器代码。

    CIL更像是汇编语言-距机器代码仅一步之遥,同时仍是人类可读的。


    差别不大。两者都是您编写的代码的中间格式。在执行时,虚拟机将执行托管的中间语言,这意味着虚拟机将控制变量和调用。甚至还有我现在不记得的一种语言,它可以以相同的方式在.Net和Java上运行。

    基本上,这只是同一件事的另一种格式

    编辑:找到了语言(除了Scala):是FAN(http://www.fandev.org/),看起来很有趣,但是还没有时间评估


    我认为MSIL不应与Java字节码进行比较,而应与"组成Java字节码的指令"进行比较。

    没有反汇编的Java字节码的名称。" Java字节码"应该是非官方的别名,因为我在官方文档中找不到它的名称。
    Java类文件反汇编器说

    Prints out disassembled code, i.e., the instructions that comprise the Java bytecodes, for each of the methods in the class. These are documented in the Java Virtual Machine Specification.

    " Java VM指令"和" MSIL"都被组装为.NET字节码和Java代码,它们是人类不可读的。


    Serge Lidin撰写了一本有关MSIL详细信息的体面的书:Expert .NET 2.0 IL汇编器。通过使用.NET Reflector和Ildasm(教程)的简单方法,我还能够快速掌握MSIL。

    MSIL和Java字节码之间的概念非常相似。


    同意,差异足够细微,可以初学者学习。如果您想从基础开始学习.Net,建议您查看一下公共语言基础结构和公共类型系统。


    推荐阅读