浅谈C# vs Java (1)

** CLR vs JVM **

1. 概念

Microsoft 一直在宣称 CLR( 公共语言运行环境 ) 是所谓得虚拟机器而并非 JVM 虚拟

机的概念。这是由于 CLR 将支持一切遵循 CTS( 公共语言规则 ) 的编程语言在其上运行并且互不干扰,从这个概念上说 CLR 相较 JVM 来说更像一个平台。

2. 编译

Java 将源码编译成为 .class 文件,通过 java 命令来运行。例如:

java test.class

而 C# 则将源码编译成为 .exe 文件。但这个 exe 文件不同于传统的 exe 文件,它是由一个清单和 MSIL(Microsoft 中间语言 ) 代码组成。格式大致如下:

PE(Win32-Portable executable) 头 --- exe 文件头

清单 --- 文件中所包含的类型和类

跳转命令 --- 跳转到 MSIL 解释器

MSIL 代码

从以上的结构可以看到, C# 同 Java 一样能够轻松被反编译,不同的是, Microsoft 还提供了用于读取编译后 MSIL 的工具 ildasm 。

另外,虽然 Microsoft 对这种结构提出了种种的好处,但是如果把 MSIL 看成是 Java 编译后的代码 ( 即 .class 文件中的代码 ) ,那么 C# 的文件结构更象是把 Java 的运行命令和 .class 文件已 exe 文件的方式封装起来。如下表:

C#

|

Java

---|---

PE 头

|

-

清单

|

关于这点将在部署一节中论述

跳转命令

|

java 命令

MSIL 代码

|

.class 文件

分析了 C# 编译结果,就会发现 C# 并没有因为编译成了可执行文件,就依附于 window 平台。从理论上说,如果有一个 Linux 版的 MSIL 解释器 ( 实际上它是 CLR 的一部分 ) 和一个 Linux 版的 C# 的编译器,那么就可以将 window 下编写的 C# 的代码在 Linux 下重新编译,于是就实现了所谓“处处编译,处处运行”。而在这工程中,保持代码编译一致性的 CTS( 公共语言规则 ) ,难怪有自由软件组织曾提议使用 Microsoft 的 CLR&CTS 构架来统一当前自由软件界的编译环境。

3. 运行

Java 早期是一种解释性语言,后来为了提高效率采用了 JIT(just-in-time) 技术,还有一些工具可以将 Java 生成特定的 CPU 的二进制代码。

而 C# 也必不可少的选用了 MSIL 和 JIT 的机制。根据不同的情况可分为 3 类:

a) 安装时代码生成 (Install-time code generation) :将当前代码完全编译成特定的 CPU 的二进制代码。之所以叫做安装时代码生成,是因为这个编译过程是在安装时进行的。

b) JIT :与 Java 的 JIT 方式相似。

c) EconoJIT( 经济性 JIT) :与 JIT 不同的是,它通过丢弃已产生出的,编译过的代码回收内存,比较适用于少量内存的手持设备。

4. 部署

Java 采用的是将包路径和目录相对应的方法,生成一层一层的目录。之后又推出使用 jar 文件封装的方式。

C# 采用的是元数据纪录的方法。所谓元数据就是上文 C# 编译结果结构中提到的“清单”。 C# 通过元数据纪录类型和类的信息,相较 Java 的目录结构和 jar 文件方式,封装性提高

了不少。不过目录结构有一个好处是显而易见,就是当有部分代码需要修改的时候,只要重新编译需要修改的代码,并覆盖相应的类就可以了。

** 一切都是对象 **

C# 和 Java 都宣称自己的一切都是对象,但是真正实现这一说法的恐怕只有 SmallTalk 。

这主要是因为将基本数据类型描述成对象所造成的代码性能方面的降低是很难让人接受的。于是 C# 和 Java 都提出了关于这一问题的解决方案。

Java 保留了基本数据类型,并为每一种类型提供了一个对应的类,如 int 型对应 Integer 类, long 型对应 Long 类。当需要用类来描述基本数据类型时,即可通过生成其对应的类,如下代码:

int n = 5;

Integer in = new Integer(n);

使用后,又可以将对应类的值赋给基本数据类型,如下代码:

Integer in = new Integer(5);

int n = in.intValue();

相对应的, C# 也采用了为基本数据类型提供对应类的方式,但在使用上采用的是开箱 (unboxing) 和装箱 (boxing) 操作。所谓装箱就是将基本数据类型转换为对应类。而开箱的作用刚好相反。

当试图将基本数据类型以一种与 System.Object 基类接口相匹配的方式使用时,系统将自动将它装箱,使之能够像一般对象一样被使用。如下代码:

int n = 42;

Int32 in = n;

开箱的代码如下:

int n = 42;

Int32 in = n;

// 注意:开箱时必须进行显示的类型转换

int n2 = (int)Int32;

有以上的例子可以看出,在一切都是对象的问题上, C# 和 Java 的解决方式是很相似,

只是 C# 封装了更多的操作细节。但是是否有系统来做这些操作可以提高语言本身的效率呢? Microsoft 的回答肯定是肯定的。

** 小结 **

以上对 C# 和 Java 在编译运行以及对象的设定等问题上作了比较,从中发现, C# 在设计上大量模仿 Java ,但在具体实现上 C# 封装了更多的细节,相较 Java 来说应该更易于使用,这大概是 Microsoft 的风格吧。

Published At
Categories with Web编程
Tagged with
comments powered by Disqus