MSIL和Java字节码之间的区别?

时间:2008-09-18 18:13:35

标签: java .net bytecode cil

我是.Net的新手,我想先了解一下基础知识。 MSIL和Java字节码有什么区别?

8 个答案:

答案 0 :(得分:71)

首先请允许我说,我认为Java字节码和MSIL之间的细微差别不应该是新手.NET开发人员的烦恼。它们都用于定义抽象目标机器的相同目的,该机器是最终使用的物理机器之上的层。

MSIL和Java字节码非常相似,实际上有一个名为Grasshopper的工具将MSIL转换为Java字节码,我是Grasshopper开发团队的一员,所以我可以分享一些我的(褪色)知识。 请注意,当.NET framework 2.0问世时,我已经停止了这方面的工作,因此其中一些事情可能不再适用(如果是这样,请发表评论,我会更正)。

  • .NET允许用户定义的类型具有与常规引用语义(struct)相关的值语义。
  • .NET支持无符号类型,这使得指令集更丰富。
  • Java包含字节码中方法的异常规范。虽然异常规范通常仅由编译器强制执行,但如果使用非默认类加载器,则可以由JVM强制执行。
  • .NET泛型用IL表示,而Java泛型只用type erasure
  • .NET属性在Java中没有等价物(这仍然是真的吗?)。
  • .NET enums不仅仅是整数类型的包装器,而Java enums几乎是完全成熟的类(感谢Internet Friend注释)。
  • .NET有outref个参数。

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

答案 1 :(得分:22)

他们基本上做同样的事情,MSIL是微软的Java字节码版本。

内部的主要区别是:

  1. 字节码是为编译和解释而开发的,而MSIL是为JIT编译而明确开发的
  2. 开发MSIL是为了支持多种语言(C#和VB.NET等)而不是只为Java编写的字节码,导致字节序在语法上比任何特定的.NET语言都更类似于SQL
  3. MSIL在值和引用类型之间有更明确的描述
  4. 可以在this article by K John Gough(postscript文档)

    中找到更多信息和详细比较

答案 2 :(得分:20)

CIL(MSIL的正确名称)和Java字节码比它们不同的更相同。但是有一些重要的区别:

1)CIL从一开始就被设计为多种语言的目标。因此,它支持更丰富的类型系统,包括有符号和无符号类型,值类型,指针,属性,委托,事件,泛型,具有单个根的对象系统等。 CIL支持初始CLR语言(C#和VB.NET)不需要的功能,例如全局函数和tail-call optimizations。相比之下,Java字节码被设计为Java语言的目标,并反映了Java本身的许多约束。使用Java字节码编写C或Scheme要困难得多。

2)CIL旨在轻松集成到本机库和非托管代码中

3)Java字节码被设计为解释或编译,而CIL的设计仅假设JIT编译。也就是说,Mono的初始实现使用了解释器而不是JIT。

4)CIL被设计为(and specified)以具有人类可读和可写的汇编语言形式,其直接映射到字节码形式。我相信Java字节码(顾名思义)只是机器可读的。当然,Java字节码相对容易反编译回原始Java,如下所示,它也可以“反汇编”。

我应该注意到JVM(大多数)比CLR(其中任何一个)都更加优化。因此,原始性能可能是首选定位Java字节码的原因。这是一个实现细节。

有人说Java字节码设计为多平台,而CIL只设计为Windows。不是这种情况。 .NET框架中有一些“Windows”主义,但CIL中没有。

作为上面第4点的一个例子,我曾经给CIL编译器写了一个玩具Java。如果您为此编译器提供以下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程序,可以输入像ilasm.exe之类的CIL汇编程序来创建可执行文件。如您所见,CIL是一种完全人类可读写的语言。您可以在任何文本编辑器中轻松创建有效的CIL程序。

您还可以使用javac编译器编译上面的Java程序,然后通过javap“反汇编程序”运行生成的类文件,以获得以下内容:

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输出进行比较,你会发现两者非常相似。

答案 3 :(得分:2)

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

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

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

答案 4 :(得分:2)

CIL aka MSIL旨在使人类可读。 Java字节码不是。

将Java字节码视为不存在的硬件(但是JVM模拟的硬件)的机器代码。

CIL更像汇编语言 - 距机器代码一步,但仍然是人类可读的。

答案 5 :(得分:1)

同意,差异很小,可以作为初学者进入。如果您想从基础知识开始学习.Net,我建议您查看公共语言基础结构和通用类型系统。

答案 6 :(得分:1)

Serge Lidin撰写了一本关于MSIL细节的好书:Expert .NET 2.0 IL Assembler。通过使用.NET ReflectorIldasm (Tutorial)查看简单方法,我也能够快速获取MSIL。

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

答案 7 :(得分:1)

我认为MSIL不应该与Java字节码相比,而是“构成Java字节码的指令”。

没有反汇编的java字节码的名称。 “Java字节码”应该是一个非官方的别名,因为我在官方文件中找不到它的名字。 The Java Class File Disassembler

  

为类中的每个方法打印出反汇编代码,即组成Java字节码的指令。这些都记录在Java虚拟机规范中。

“Java VM指令”和“MSIL”都汇编成.NET字节码和Java代码,这些都不是人类可读的。