NG体育的答案不错。我想就所谓“Microsoft J++”到底是什么稍微补充几点。
当时(Sun JDK 1.0.2)的Java跟现在的Java不可同日而语。别提标准不标准,当时的Java毛都没有,很多东西所谓“标准”就是“Sun怎么实现”。
为什么Sun要告微软?微软“不乖”,“擅自”扩展Java让它在Windows上变得更好自然是一方面;另一方面Sun对它的Java合作伙伴们普遍态度恶劣,非常傲慢和小心眼,这才是更重要的方面。
另外,想从别的侧面看看当年Sun的行为,看看1997年Sun在benchmark上作弊的事情:
Microsoft J++是外界对微软所实现的Java的开发套件和运行时环境的统称。微软自己其实并没有一个叫做“Microsoft J++”的产品(或语言)。微软一直觉得自己实现的就是Java语言,只是稍微根据Windows环境的需要“增强”了一点而已。
微软在JDK 1.0.x时期就获得了Java的授权,将Java移植到Windows平台上。当时的Java真是烂得掉渣,JVM的速度又慢,Java核心库的功能又是要啥啥没有:
例如说能用的容器数据结构就只有Vector、Stack(包装了Vector)、Hashtable(不允许null值)、BitSet,连LinkedList都还没有——“谁会要用链表呢”。
嗯对,JDK 1.0.2的时候连反射都还没API,g.reflect也还不存在。Java语言里“接口”这个语言结构也还不存在。
于是让Java能够更好的利用Windows上已有的资源,真正在Windows上成为一等公民,微软给Java添加了:
微软版的RNI在Sun版的JNI之前就已发布,自然就不大愿意再实现一个功能非常相似的东西。但微软决定不在MSJVM里实现完整的JNI成为了后来打官司的关键因素之一。
Visual J++,这是一个实际存在的产品的名字。它是一个用于开发Java应用程序的IDE,里面还包含有IE3.0之类的“附属物”。Visual J++有单独发布的版本,后来被整合到Visual Studio里发布。
有个有趣的工具叫做 jexegen。顾名思义,它用于为Java程序创建一个可执行程序,把Java程序所需的Class文件打包在生成的exe里。这跟后来.NET Assembly的做法很接近:它是一个PE文件,不过启动之后马上会去加载MSJVM来执行打包的Class文件。能生成出可执行文件让Java写出来的程序能更符合Windows的用户习惯。
jvc 是微软自己实现的Java源码编译器,应该是用C++实现的(求证)。
它的编译速度非常快,而且编译时会做许多优化,编译出来的代码质量也比较高。
相比之下,同时期Sun的javac是用Java实现的,编译速度慢一些;虽然也做一定量的优化,但没 jvc 做得深。
(跟后来的Jikes RVM不是同一个东西)地位相似。两者都用native语言实现(Jikes用C++),编译速度都比较快,而且都做比较多优化。
jvc 支持所有标准的Java语言特性,外加支持如delegate、J/Direct之类的微软扩展的特性。
话说有个黑历史非常搞笑:Sun在控告微软的jvc不兼容Java规范的时候,指责jvc生成的Class文件通不过TCK1.1;然后微软不但说明Sun没用对命令(故意打开了微软扩展来测试),而且进一步说明Sun的javac其实也不能完全通过TCK1.1;关掉了扩展的jvc能通过的TCK1.1测试比Sun的javac能通过更多。
这是微软实现的JVM。最初的代码来自Sun授权的Sun元祖JVM,后来被魔改成Windows上最快的JVM实现。
对象模型:Sun JVM的对象模型把“对象头”放在了handle里,使“对象头”跟对象实例数据分离到不同的地方了。MSJVM去掉了handle这层间接,于是把对象头与对象实例数据重新“粘”到了一块。关于MSJVM的对象模型,我在另一个回答里简单提了一下:为什么bs虚函数表的地址(int*)(&bs)与虚函数地址(int*)*(int*)(&bs) 不是同一个? - RednaxelaFX 的回答
GC:准确式的、分两代的copying GC。文档里还专门说了没使用mark-compact算法。当时的Sun JVM使用的是半保守式、不分代的mark-sweep(带可选compaction) GC。
对象同步:使用synchronization block而不是老Sun JVM的monitor cache。在对像头里包含有一个指向synchronization block的指针;该指针位于对象的负偏移量上。后来的CLR的对象头采用了同样的布局。在对象头里持有这样的指针大幅减少了查找对象的monitor的事件。Sun JVM是维护一个全局的用hash table实现的“monitor cache”,把对象的handle强制转换成int当作key去查找这个cache里的monitor,每次查找都是一个hash lookup。
线程:使用native线程,管理线程用的数据结构稍微调整过。Sun JVM在Windows上的版本用native thread,而在Solaris上的版本则是使用green thread(JVM自己调度的用户级线程)。
添加了JIT编译器:Sun JVM在JDK 1.0.x的时候只有个很简陋的JIT编译器接口,但没有发布JIT编译器的实现。MSJVM改造了这个接口并且提供了一个当时性能还不错的JIT编译器实现,而且配合准确式GC提供必要的信息。
RNI:在Sun JVM的native interface的基础上衍生出的一套native interface。
MSJVM基本没怎么改动的可能也就是解释器的核心循环了。原本在Sun JDK 1.0.2的时候,Sun JVM的解释器循环用纯C实现,写得很直观但性能很渣;到Sun JDK 1.1.0的时候
,写得比较高效,所以也就没啥必要魔改这部分,小改动然后直接用就好。顺带一提,Sun JDK 1.1.0的JVM的解释器,在x86上的版本是Intel贡献给Sun,而不是Sun自己写的⋯呃呵呵。
据说James Gosling原本自己写过一个JIT编译器,但是没发布被抛弃了。不知道这跟sunwjit是啥关系呢。
里提到的,微软里其实还有过一小撮人做过一个非正式项目,是写一个全新的、“clean-room”(不衍生自Sun的代码)的JVM原型。这个项目最后没有进入产品。或许如果当年Sun没有禁止微软开发新版本Java的话,微软也会像IBM开发出全新、clean-room的J9 VM一样有自己独立的JVM。
然而历史没有如果。那个clean-room的JVM原型为后来的CLR的研发积累了不少经验。
J++是微软的Java实现版本,表达式、关键字、语法规约都和Java一致,符合Java的语言规范,2004年1月停止支持。
Sun一开始是授权微软可以使用Java的,随后对微软提起了商标侵权的诉讼,因为Sun的商标授权协议里要求实现必须是“兼容的”,才能使用Java的商标。而微软的MSJVM没有通过Java的符合性测试。最终Sun和微软和解,条件是J++只能开发到1.1.4版本,并且停止MSJVM的分发和下载。
J++的部分技术被回收利用,吸收到了台,演化成为J#,最终到现在的C#。
可以看到,J++对Java做了大量的改进,这些改进后来都吸收到了.Net平台以及C#语言当中。
从法律和道义的角度来讲,微软违约很不厚道这点毋庸置疑,以下主要是从技术的角度来进行评价,一言以概之,时间证明Sun并没有站在先进生产力的一边。
最核心的槽点,可能就是J++搞私有API/不跨平台。但这直接带来了性能上的提升,虽然影响了跨平台,但作为一种工程上的trade off,不一定是坏事,想想当年的电脑有多慢吧。现在微软官方的.Net CLR实现出于性能考虑,同样把不少工作推到了平台相关的native代码层上,也并没有影响mono实现跨平台,可见这个槽点根本就不算个事。
J++可以认为一直延伸到了今天的.Net一系的产品线,所以要评价J++是怎样一种存在,在很大程度上需要把今天的C#/.Net和Java对比。现在Java和C#相比,除了(官方)跨平台,以及因为起步早+成本相对可以较低所以行业应用较多以外,毫无撸点,语言特征方面C#更是甩Java几条街。
由于mono项目的存在,使得C#跨平台根本不是问题,唯一影响其广泛在开源社区被采用(如默认在Linux发行版中集成)是因为开源社区普遍不待见微软,并且对微软的CP(Community Promise,微软承诺允许开源社区自由的对包括C#在内的部分微软专利产品、规范编写自己的实现)持保留意见。但这并不影响mono的广泛使用,不少的应用程序、开发框架都采用mono作为脚本引擎,比如Unity3D引擎。
最近在研究把CoffeeScript编译到CLR上执行,顺便再说下运行时环境,JVM vs CLR。这么多年来,产生了一些编译到Java byte code,然后在JVM上运行的的语言,比如Scala,但并没有证据表明Sun一开始的设计就考虑到了JVM大生态圈的建立。而.Net CLR则提供了一系列相当凶残的方案,比如DLR(Dynamic Language Runtime),编译器的开发者只需要解析出代码的AST(Abstract Syntax Tree),再加上少量的glue code,就能把一种新语言target到.Net上运行,完全无需操心代码生成、代码优化、runtime等等需要花费大量精力的编译器后端环节,并且能在后续.Net升级时,自动获得新的改进(比如更加NB的代码优化算法)。这代表什么?一个开发者甚至不需要把《编译原理》一书读完,翻了前几章能写个词法分析和语法分析,会解决Grammar的Shift-Reduce conflict,就能撸出一个能用于生产的以CLR为目标平台的编译器出来。不管最后结果会如何,从技术的角度而言,微软的解决方案是更有利于开发生态的建立。
从这些角度来看,J++虽然不能说是完爆Java,青出于蓝四个字还是能提的,进步的态度和力度都是值得称道的。微软在当年受制于Sun的许可协议时,尚且大胆的对Java进行扩展改进,后续衍生的C#/.Net平台的每个新版本的演化力度都不弱,反观Java这么多年来的进展,不免让人呵上一呵。
和微软现在C#的Community Promise相对比,当年Sun给微软的Java授权协议,不得不说实在是太狭隘了,最终在一定程度上限制了自身的发展。
简单地说NG体育,就是sun授权微软用java,打算是里利用微软的知名度,扩大java的使用率。结果发现通过微软平台开发的java程序,只能在win平台可以用,而在其他平台总有这样那样的问题。于是谈崩了,就是这样。
J++ 是对 Java 的一些修改,或者叫改进,大部分兼容 Java,不过对某些特性并不 100% 支持,当然那些改进都只能在微软的平台下存在。
而这个思想违背了 Java 的根基,毕竟 Java 的目标是一次编写到处部署,但如果大家都用微软的 J++ 去,那么意味着不同平台移植还是涉及到修改代码重新编译,跟 C 成了一样的性质, Java 的跨平台特性就不存在了,这就意味着 Sun 的 Java 就被釜底抽薪了,一旦这个釜底抽薪完成,这个世界上就没 Sun/Java 什么事了。所以可以理解为,为了 Java 的生死存亡,Sun 必须告微软。
之所以现在 Java 能够大量的用于服务器端,很重要的因素还是因为 Sun 保持了 Java 的纯净性,使得它仍然能够跨平台,要知道服务器有一部分甚至都不是 Linux,而是私人定制的 Unix,跨平台部署很多时候非常重要,当然最痛恨它的自然是微软,你们都到 Linux/Unix 里面部署服务器了,我微软的服务器卖给谁呢?
从微软的角度,动摇 Java 的根基当然是绝对正确的选择,而从业界的角度,微软想把 Java 也变成捆绑到微软平台的东西,自然也是绝对不正义的。
至于说 Mono 可以用于跨平台,我只能说呵呵。Mono 平台能兼容多少 C# 应用?以那种兼容性敢部署自己的生产系统上去么?还别说本身是微软的知识产权,你开源制造一个 C# 一个 .NET 平台微软可是随时能告你专利侵权的,微软虽然口头上承诺了不告Mono,但这并不等于说微软无权告Mono,也不等于说微软授权给Mono做这件事情了。所以如果你想用 Mono 干活,无论是其兼容性,稳定性,还是法律风险方面,都得不偿失。真的喜欢 C# 和 .NET,请直接用微软平台,当然这也就意味着你与 Linux 的世界无缘了。
虽然 C# .NET 很优秀,可是这个世界上毕竟还有人不愿意被绑在微软的平台上,所以自然会有人它,这,无可厚非。
其实若干年后,Google 的 android 似乎做者类似的事情,重新分裂了 Java,为什么这次的结果就不同了呢?一方面是时代不同了,另一方面是因为 android 本身开源。而微软的 .NET 平台不是开源的。即便 Google 消失了,android 本身仍然属于全人类。而 .NET 却不是。
微软的 C# 很牛,.NET 很厉害,技术架构很先进,一切都很好很好很好,但,它只属于微软,不是开源的,不属于全人类,大家不愿意选择一个受到一个商业公司完全控制的技术,就是这样。
有人说跨平台很扯,那么大家今天不谈跨平台了,谈谈一个简单的问题:如果我就是想在 Linux 平台上选一个开发环境, C# 是首选么?明眼人都应该明白这个道理, mono 至少不是一等公民,是属于微软没把它当亲儿子,Linux 社区更没把它当自己人的存在。
微软要的是一个微软作为一等公民的环境,如果你使用 C#,微软的环境才是首选,Linux 只是需要跨平台适配的时候才勉强用一下的。——但现实是,大家需要一个用 Linux 作为一等公民的环境,需要一个在 Linux 上开发调试,微软平台是否支持都没什么关系的环境。
那么,为 Linux 平台保留一个商业可用的环境,就显得尤其重要了。即便它现在的接盘侠是 Oracle 也不能改变这个事实:Java 在 Linux 上的表现,目前大公司可以信赖和依赖它,而一旦依从微软,这一切将不复存在。
一个修改版的Java,不再能一次编写到处运行的java(虽然这也是在吹nb)。
表面上来看sun告微软修改了java,降低了可移植性,违反了协议。实际上如果微软仅仅是降低了可移植性,那么j++就没有任何战胜java的希望。但是因为Anders Hjelsberg这个bug一样的存在,j++在微软的虚拟机上跑的飞快,j++甚至于可以生成本地代码,特定情形下跑的比c++还快,这简直不能忍啊,都用更快的j++了,谁还用java?