炎 的个人资料知更鸟的巢照片日志列表更多 工具 帮助

日志


3月24日

第二讲 .Net与Java——中间语言简介

第二讲 .NetJava——中间语言简介

 

Java.Net的共性:中间语言

 

如果你比较熟悉Java的编译原理的话,你一定会对bytecode这个单词非常熟悉。确实,Java的最大特点并不是它是一个完全基于现代OO理念的编程语言或是其简单而容易上手(事实上我不得不承认,Java确实比C#要简单,虽说C#已经非常简单了……),而是Java是并不直接把源代码编译为目标代码,而是先编译为一种中间语言:Java Bytecode。在实际执行的时候,Java的解释器JVM,向计算机解释这种代码,从而达到执行目的。在这里不想阐明所谓“编译”和“解释”两个专业术语。但是有一点希望读者了解:编译将生成目标代码,实际执行它,所以效率要高些。解释则不生成目标代码,效率低些。简单举个例子,如果说编译相当于书面翻译的话,解释则有点像口译。

 

反观.Net.Net也采用了编译为中间语言的方法,.Net的中间语言称为IL。这点上,.Net是吸取了Java的长处。同时,也拓宽了中间语言的使用范围。例如,.Net的语言互操作性,就是在IL层面上实现的。也就是说,不管你是用VB.NetC#,还是J#Managed C++,最终你编译得到的,都是IL。这就是.Net可以使用多种语言编些项目的秘密所在了。.NetJava的不同之处在于,编译为中间语言之后,JavaJVM来解释之,而.Net则使用.Net特有的JIT编译器编译之。所谓JIT(Just In Time),是指.NetJIT编译器并不一下把整个应用程序编译完毕(如果这样的话,应用程序将会有一个很长的启动时间),而是只编译将要执行的那一小段。代码编译过之后,得到的目标代码就可以存储在内存中,下次再执行到这里,就不需要重新编译了。微软认为这样编译,要比一次编译效率要高得多,因为很多代码并不是每次运行都会执行到,这样,这部分代码就不会被编译。同时,用一点编译一点带给用户的感受也是很好的,因为每次都指编译很小的一块,用户感受到的就像是在直接执行一个机器语言可执行程序一样。这就解释了为什么.Net程序虽然是一个与Java同样不直接编译为机器代码,但是运行效率却几乎和内部机器代码一样快。事实上,在相当长的一段时间内,.NetJava有压倒性的效率优势,直到Jdk1.5出现之后,Java也采用了JIT编译方式。(但是现在,.Net的程序跑起来还是要比Java快一点。)

 

为什么要采用中间语言——平台无关性的实现

 

看了上面的介绍,读者可能要问,为什么要非如此大的周折,采用两次编译的方法,把效率降到这个程度然后再想尽办法提升效率。一个重要的原因在于,编译为中间语言可以实现一个重要特性:平台无关性。

 

平台无关性是指:你写的代码,所实现的功能,与你所采用的平台无关。举个例子,Java是一种平台无关性语言,所以你想绘制一个窗体,在上面显示一个Hello World,那么你写的代码不需要任何更改,就可以同时在WindowsLinux,或是其他有jdk存在的操作系统中执行。目前,在时下流行的大多数操作系统中,都有相应的jdk存在,Java当年推出的时候的豪言壮语:“Write once, run everywhere.”在某种程度上说已经实现了。(当然,这句话很快就变成了:Write once, debug everywhere. 平台的无关性并不象说说那么简单。)

那么平台无关性是怎么实现的呢,这就与中间语言分不开了。中间语言可以经过精心设计,使得其本身与平台无关。当framework尝试去解释/编译中间语言的时候(对于.Net而言,完成这个工作的是CLR,对于Java而言,是JVM),将其转化为对应平台可以接收的机器语言代码,这样就可以实现平台无关。比如,中间语言有一个指令表示绘制一个窗体,那么,在Windows下,它被解释为某条(或很多条)Win32API指令,而在linux下面,它则被解释为linux可以接受的指令(小鸟不会linux编程……),这样就实现了平台无关性。

 

需要说明的是,目前Java已经相当程度地实现了平台无关性,而对于.Net而言,平台无关性还只是一种可能——.Net采用了与Java相似而又相对优秀的技术,但是,目前,实际上,除了Windows系列操作系统(包括可以运行于手机的Windows)以外,并没有哪个操作系统存在.Net Framework。但是,很多大牛们正在积极准备,编写基于其它平台的.Net Framework。一个很好的例子就是Linux下面的Mono项目,目前Mono还处于测试阶段,但是包括remoting.Net的重要功能,都已经可以很好地在Linux下面实现,如果你编写的仅仅是dll或是Console程序的话,那么你的程序应该可以在Linux下面运行。最新的消息表明,Mono的图形界面控件库也已经搭建完毕,相信很快,.Net就可以真正实现LinuxWindows的平台无关性。

 

中间语言的其它特性

 

使用中间语言不仅仅可以实现平台无关性或是前面所提到的高级语言的互操作性。它还有很多其他重要特性:

1.       性能优化。传统的编译器会优化代码,但是它们的优化过程独立于代码所运行的特定处理器和环境。这是由于,传统的编译器直接将软件编译为机器可执行的内部代码,编译器并不知道该程序将运行的处理器类型。例如,你想编译出来的程序可以利用Pentium III的新特性,那么你就必须要放弃Pentium I,II的用户。但是,使用了中间语言之后,实际的编译过程发生在客户端,编译器知道该程序将在什么环境下运行,于是编译器可以最大程度的利用新型处理器的新特性,编译出最优的目标代码。

2.       基于代码的安全性。传统的目标代码(机器语言)非常抽象,机器不可能理解每条语句的意义,而只能照着执行。而采用中间语言之后,基于代码的安全控制成为可能。由于中间语言相对于机器语言比较具体,编译器在目标机器上编译并执行时,可以在编译之前检查,该程序是否具有执行该操作的权限。

 

这次就讲这么多,事实上关于中间语言,还有很多特性,计划放到下一讲,介绍.Net的特性时说,包括垃圾收集器和应用程序域,还有AttributeAssembly的介绍。

第一讲 .Net 简介

受人邀请,在bbs上做一个关于.Net的扫盲讲座,既然这样,就充实下我可怜的space吧.........


 

写在.Net之前

 

说到.Net,绝对不能不说的两个东西,就是COMJava。不熟悉Windows编程的人可能会不知道COM这个东西,但是如果你在上世纪在Windows下面尝试编写组件或者是执行程序而不使用Visual Basic或者Delphi(事实上VB对程序员发挥的制约是非常大的,基于COM但不透露COM本质的VB不仅仅创造了无数一知半解的程序员,也造成了无数莫名其妙的问题。一个经典的例子就是comdlg32.ocx缺失,这里不想跑题太多,只要你在Google上搜一下这个文件名,你就会明白这个问题的普遍性),那么你对两个名词一定会深恶痛绝:一个是MFC,另一个就是COM

 

MFC是什么,如果你知道API的话,那么事情好办:MFC就是对API的封装。个麽API是什么?Application Programming Interface,简单来说,就是程序操作的接口,如果我的程序要读取一个文件,那么我要使用一个读取文件的API。因为从计算机体系结构来说,应用程序应该通过操作系统来访问物理磁盘(正在学习机原的孩子们注意了,机原和操作系统涉及这方面的问题),那么这个访问的渠道,就是API。因为直接用API太烦了,所以出现了MFC,它封装了一些常用操作,实际是对API的封装和简化。但是,MFC还是太复杂了,如果你去看一个基于MFCHelloWorldC程序,它的长度将达到100行——你需要了解很多关于操作系统本身的内容,才能熟练的使用MFC。以我个人的看法,Windows下面的C程序(使用MFC),不能被称为C,它太丑陋了,根本就是另一种语言。反过来,在Linux下面的C程序员就要舒服得多,这也是这么长时间来,Linux一直被程序员所钟爱的原因。

 

下面说COMCOM是什么,COM其实有点类似于一种平台,它不是一种语言或是一种编程技术,它制定了一种约定,凡是符合这种约定的组件(比如说一个dll函数库,或者一个ocx组件),都可以相互通信,互相调用。这就意味着,你用C写一个程序,用gcc编译为exe,然后你再用Delphi写一个组件,编译为ocx,只要他们都符合COM规范,那么,它们之间就可以相互通信,那个用C写的程序就可以在运行时调用那个用Delphi写的组件。这在当时是一个创举,用某本书上的话说,COM将动态加载代码和类型系统已相当一致的方式有机结合在一起。但是可怜的Windows程序员们并没有因为COM的到来而日子好过一点(其实还是稍微好了那么一点点),COM引进了“组件”这个概念(component),使得程序员们在Windows下面可以以相当OO(面向对象技术)的方式,编写和复用相当多的代码。(否则你杀了微软的程序员他们也写不出Word这种变态的东西。)COM带来了一个巨大的问题:Dll Hell。具体这个问题是非常复杂的,如果你有兴趣的话可以Google “dll hell”,你会找到足够的条目。简单来说就是,因为大家都用这些组件,组件有版本,你用1.0,我用2.0,但是只能注册一个,如果2.0能够兼容1.0还好说,但是如果不能兼容,个麽你就废了。举个例子,你安装了一个游戏甲,它替换了某组件A,但是该组件A是另一软件乙所必须的,但是新版本不向后兼容,于是软件乙就不能用了,而且出错还是莫名其妙的。你被郁闷了,于是把软件乙重装了一遍,于是游戏甲又不能用了。关键是你根本不可能知道到底是哪一个组件出了兼容性问题。现在大家该明白所谓Dll HellHell一词从何而来。

 

.Net的起源

 

基本可以认为,.Net是为了替代COM而诞生的。事实上,在.Net诞生6年后的今天,原始COM已经几乎被消灭了。(当然COM+等还将持续很长一段时间。)将来的Windows程序员将再也不会遇到上世纪末那些疯狂而变态的兼容性问题。微软从很早就开始注意到COM所带来的一系列问题,旗下的COMMTS小组(一群大牛)计划开发一个新的平台,命名为COM3。就在选定该名称之后不久,微软的多个研究小组(更多大牛)认为,在特定的Microsoft平台下,COM3这个名字并不合适。随即将其更名为CORCommon Object Runtime)(这帮人一定都是OOcon),在其开发过程中,还采用过COM+等其他名称。在其第一个beta版发布之前,最终定名为CLRCommon Language Runtime,关于CLRCOM在技术上的区别,这里不讨论(否则看几个晕几个),但是,CLR确实有效的解决了COM的相当多的问题(但不是全部,也不可能是全部)。CLR就是.Net的核心。

 

.Net的特点

 

COM时代开始,微软的野心就从没有局限在一种语言上面,微软希望能够建立一个平台,在此平台上,各种语言都可以为微软所用,编写相应的Windows Application。从现在的眼光来看,通过.Net,微软(至少从部分来说)达到了这个目的。CLR在创立之初就有一个雄心勃勃的目标:在高级语言层面实现语言的互操作性(相比之下COM的互操作性是建立在编译之后的机器语言或者说二进制代码之上的)。在微软自身的.Net Framework中,包含了如下几种语言,C#, VB.Net, VC++, J#

 

C#是微软专门为.Net设计的一种全新的语言,它采用C Style(就是写出来和C很像,事实上,很多语言,例如Java,也是C Style的)。它还是一种基于现代OO设计的语言(Java也是,所以C#Java的相似程度异常之高)。

VB.Net是由原有的VB6经过改进得到的,学过VB的同学可能对VB比较熟悉。但是从VB6VB.Net的改进是如此之大,以至于你可以把VB.Net完全当作一种Basic家族的全新语言。(事实上,完全OO化了的VB也是非常好用的~~~

VC++在进入.Net时代之后,也发生了脱胎换骨的变化,之前的VC++6虽说相当简单易用,但是却不符合C99等重要标准,VC++写的程序用gcc等边一起来编译就不通过(这也是相当多的专业程序员摒弃Visual Studio而采用editplus或者eclipse+cdt等平台来编写C++程序的原因)。这是由于VC++6中含有许多微软对Windows的特定扩展。从VC++2001到现在的2005, VC++发生了重大变化:分化为两支:一支为符合C99标准的标准C/C++;另一支不妨称为Visual C++ .Net,即Managed C++。可以像其他的C/C++编译器那样生成正常的exe文件,也可以生成符合.Net标准的可互操作的.Net可执行程序(也是exe……)。

 

J#是一种改编自J++的语言,使其符合.Net标准的要求(也就是CLR),而J++可以理解为微软版的Java。但是由于某些原因,J++被从Java的大家族中开除了。所以现在J#也是异常可怜的,用的人很少很少~~

高级语言层面的平台互操作性是.Net最令人激动人心的一点,你可以用VB.Net编写界面,随意调用你用C++或是C#编写的底层组件支持。在这之前,不同语言的互相调用是非常困难的。使用.Net,你可以充分发挥各种语言的优点,使得程序员的负担大大降低。涉及到网页编程之后,这一点更加明显,利用ASP.Net,你可以用C#VB.Net这种OO化的高级语言(相对另一个阵营,大多数人还在使用perlphp)编写网页,然后直接调用你用C++/C#写出的某些库(可能是同一个项目,你写了WinForm形式的GUI,又写了网页支持)。在这些环境下,.Net的优势就无人可比了。

 

本来准备介绍一下IL,再比较一下Java,不过居然莫名的就写了这么多了。算了,下次再写吧~~