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

use*_*055 78 .net java cil bytecode

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

Mot*_*tti 73

首先请允许我说,我不认为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有outref参数.

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

  • @Oak:Java注释只允许传递数据,而.NET属性是完全支持的类,它可能具有逻辑,最重要的是实现接口。 (2认同)
  • .NET 中的值类型有时可能会在堆栈上分配这一事实与它们具有*值语义* 的事实相比显得微不足道;每个值类型存储位置*是*一个实例。相比之下,Java 中的每个存储位置要么是原始对象引用,要么是混杂对象引用;没有其他类型。 (2认同)
  • 想知道他们如何比较性能明智?例如,MSIL 比字节码解释得更快吗? (2认同)

Guy*_*uck 22

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

内部的主要区别是:

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

K John Gough本文中可以找到更多的信息和详细的比较(后记文件)


Jus*_*tin 20

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 ;
    }
}
Run Code Online (Sandbox Code Playgroud)

我的编译器将吐出以下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
   }
}
Run Code Online (Sandbox Code Playgroud)

这是一个有效的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
}
Run Code Online (Sandbox Code Playgroud)

javap输出不编译(据我所知),但如果你把它比作CIL输出上面可以看到两个非常相似.

  • 事实证明,已经尝试创建人类可读/可写的Java汇编语言.我找到的两个是[Jasmin](http://jasmin.sourceforge.net/)和[Java Bytecode Assembler](http://tinf2.vub.ac.be/~dvermeir/courses/compilers/javaa/) (2认同)
  • 我在这里写了一个更好的.与Jasmin不同,它旨在能够反汇编和重新组合任何有效的类文件.https://github.com/Storyyeller/Krakatau.我认为微软提供标准汇编程序而Java程序员必须自己编写汇编程序会更准确. (2认同)

GHa*_*Had 2

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

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

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