83

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

4

8 回答 8

78

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

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

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

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

于 2008-09-18T19:27:22.600 回答
24

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 点的示例,我不久前为 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 程序,可以输入到 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."<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 输出进行比较,您会发现两者非常相似。

于 2012-02-06T03:15:52.803 回答
23

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

内部的主要区别是:

  1. 字节码是为编译和解释而开发的,而 MSIL 是专门为 JIT 编译而开发的
  2. MSIL 旨在支持多种语言(C# 和 VB.NET 等),而 Bytecode 仅针对 Java 编写,导致 Bytecode 在语法上更类似于 Java,而不是 IL 与任何特定 .NET 语言的相似性
  3. MSIL 在值和引用类型之间有更明确的描述

更多信息和详细比较可以在K John Gough 的这篇文章中找到(附言文件)

于 2008-09-18T18:29:14.893 回答
2

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

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

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

于 2008-09-18T18:17:52.097 回答
2

CIL aka MSIL 旨在供人类阅读。Java 字节码不是。

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

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

于 2008-09-18T18:18:00.693 回答
1

同意,差异很小,足以让初学者难以接受。如果您想从基础开始学习 .Net,我建议您查看 Common Language Infrastructure 和 Common Type System。

于 2008-09-18T18:22:27.670 回答
1

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

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

于 2008-09-18T18:23:36.653 回答
1

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

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

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

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

于 2008-11-30T11:26:35.473 回答