Java 不适合编写桌面应用,这是事实还是偏见? 本文作者以个人视角对 Java 桌面发展历程做了回顾,内容来自他在上世纪九十年代后期担任 Java 开发者时的所见所感,主要讲述曾经的“杀手级”桌面语言 Java 是为何从 21 世纪开始颓势尽显、步入衰落的。值得一提的是,作者如今在做一款开发者友好型 Java 桌面部署工具(jDeploy),其实他还是希望 Java 可以重拾风采,再度变得对桌面开发具有吸引力。
我的大学时代正好赶上 2000 年之前的最后那几年,当时 Java 是计算科学专业里的官方语言。虽然也有几门课程要求使用 C 和 C++,但所有基础知识教学都是围绕 Java 语言来设计的。为了防止有读者朋友较真,我再说得更准确些:这些课程会用 Java 语言来教学,不是说只教 Java。
其实大学的计算机科学课并不教授特定的编程语言,教学内容主要是相关概念,再使用时下流行的编程语言来演示这些概念,所以学生们得拿出课余时间掌握编程语言。也有些课程要求更严格,比如“这份作业必须使用 Java 完成”,但大多数高级课程就不再做此限制,大家想用什么语言就用什么语言。(有些作业需要使用特定的库或者编程语言。我还记得有一份作业就是用 pthreads 库为操作系统分配线程,相当于强制使用 C 语言。)
我上大学那会,对 Java 的认知还仅限于 Applet。我既不清楚 Java 在行业里是什么地位,也不知道它跟其他编程语言相比到底有什么优势。而且越是深入学习,我就越觉得 Java 这东西有点名不副实——它更像是种玩具语言,毕竟那些“真正”的严肃开发都是用 C++这类语言实现的。反正系里总有一帮故作深沉、头发胡子一大把的家伙,总爱吹嘘跟 C++一比、Java 屁都不是。
他们倒也不是胡搅蛮缠,最常见的理由就是“Java 很慢”。相信任何用过 Java GUI 应用程序或者包含 Java Applet 网页的朋友都同意这个观点。那时候用 Java 编写的桌面应用程序就只有开发工具,我能想起的就是 ArgoUML 和 NetBeans,它们确实不好用而且速度很慢。那种慢,就像是双脚陷进了泥潭——无论是上下滚动还是打开菜单,所有操作都有“粘粘”的延迟。
但支持 Java 的教授们则坚持认为,只要配合即时编译,Java 也是可以快起来的。而且在编译了代码路径之后,“理论上”它的运行速度可以追平甚至超越 C++。但我们这帮学生根本不买账,单纯觉得他们是在嘴硬。
另一个让人感觉 Java“不上档次”的原因,在于我们开发的应用程序都不是本机应用程序。Java 构建的应用程序只是一堆.class 文件的集合;哪怕再“高阶”一点,生成的.jar 文件也只能在安装了 Java 的计算机上运行。相比之下,其他学校的朋友们展示的项目就洋气多了,这些可是货真价实的可执行文件——双击之后,它们就像真正的专业应用程序那样开跑,有程序容器、也有屏幕顶端菜单,这才像话嘛。
我记得自己问过一位教授关于 Java 能不能生成本机可执行文件,他的回答是“为什么非得这样?生成本机可执行文件,Java 的跨平台优势不就没了吗?”
如果真的想把应用程序部署成桌面程序,他建议我研究研究 Java WebStart。这样不用本机程序包,Mac 和 Windows 用户也能顺利安装我的应用程序。WebStart 听起来挺有搞头,但我还是觉得跟自己的真正目标不太相符。毕竟就算可以用 WebStart 分发应用程序,用户也仍然需要事先安装 Java。我承认,当时已经是 2001 年,大多数计算机都预装了 Java。但跟直接双击就能打开,这种体验仍然不够好。
另外,在亲自尝试了一些 WebStart 应用程序之后,我发现它的表现也就那样。应用程序的打开速度还是慢,因为启动后需要先下载更新;这些程序也没有被正确集成到操作系统当中。虽然 WebStart 也提供在桌面上为应用程序保存执行别名的功能,但效果不好。
我相信那时候肯定已经有第三方工具能把 Java 应用程序成本机可执行文件,但不光会占用大量资源、而且绝对“只支持 Windows”。我也关注过 GCJ,这款 Java GNU 编译器宣称能把 Java 编译成机器码。但它只适用于 API 子集而且不支持 Swing——所以用户就只有两个选项,要么使用本机 GUI 工具包、要么干脆不要 GUI。
所以我心里有了答案:至少在当时,Java 桌面开发已经是死路一条,唯一的用处就是写点小程序——问题是跟 Flash 这类更轻、更快的技术相比,Java Applet 的优势其实也已经不明显了。
虽然我这份“编年史”没那么详尽,但要谈 Java 在桌面端的发展历程,杀手级应用 Applets 肯定是个绕不开的话题。
Applets 在 1995 年那会确实颇具开创性,它们首次让用户在网页之内看到了交互式的 2D 图形与动画。最初(Java 1.0 时代),Java 解释器是被内置在浏览器当中的;但不久之后,就改为通过插件调用系统中已经安装的 Java 运行时。
最早的小程序嵌入起来非常简单,直接把.jar 或者.class 文件上传到 Web 服务器、再向网页中添加<applet>标记就行。遗憾的是,这种便捷性很快就消失了。随着 Java 新版本的发布和 IE 浏览器的出现,嵌入小程序所需要的 HTML 代码越来越复杂,需要针对不同的浏览器和 Java 版本使用不同的标签。虽然<applet>标签号称可以在“多浏览器”环境下正常嵌入小程序,但 IE 上实际使用的却是<object>标签,而 Mozilla 上使用的则是<embed>标签。
于是之前的嵌入方法
<APPLET code="MyAppletClass.class" archive="Applet.jar, EJB.jar" width="600" height="500" ></APPLET>
就慢慢变成了:
<OBJECT classid="clsid: 8AD9C840-044E-11D1-B3E9-00805F499D93"
width="600" height="500">
<PARAM NAME=CODE VALUE=MyAppletClass.class>
<PARAM NAME="archive" VALUE='Applet.jar, EJB.jar'>
<PARAM TYPE="application/x-java-applet;version=1.5.0">
<PARAM NAME="scriptable" VALUE="false">
<PARAM NAME="cache-option" VALUE="Plugin">
<PARAM NAME="cache-archive" VALUE="Applet.jar, EJB.jar">
<COMMENT>
<EMBED type="application/x-java-applet;version=1.5.0" CODE=MyAppletClass.class
ARCHIVE="Applet.jar, EJB.jar" WIDTH="600" HEIGHT="500"
scriptable="false">
<NOEMBED>
</COMMENT>
</NOEMBED>WebSphere Java Application/Applet Thin Client for
Windows is required.
</EMBED>
</OBJECT>
如果系统上还没安装 Java,那情况就复杂了,几乎没有比较体面的处理方法。因为嵌入代码是由 NetBeans 生成的,所以小程序的构建过程相当复杂、需要由 JavaScript 检测系统中是否安装有 Java。如果没有,则提供指向 Sun 网站的 Java 下载链接。
直到 Java 1.3 版本,小程序的用户体验都非常糟糕,以至于 Applet 只能在系统管理员完全可控的客户端软件环境中才能使用。于是乎,靠 Java Applet 在网页中添加简单交互的计划基本破产。
时间快进到 2001 年,小程序的生命基本走到了终点。Flash 凭借着更简、更轻便、更快捷,取代 Java Applet 成为浏览器媒体交互的业界标准,也获得了更广泛的安装基础(我记得当时 99%的计算机都安装了 Flash)。
不止如此,小程序还大大败坏了 Java 的名声,其中很多安全漏洞都被宣传成“Java 漏洞”。这就给人留下一种错误印象,即任何用 Java 编写的东西都是潜在的安全威胁——虽然实际上这些“漏洞”只是小程序自己的问题。尽管之后很多年仍时不时能看到 Java 小程序的身影,但它在人们心中早已成了过时技术的代名词。
我一直觉得 Applets 算不上可行的桌面应用程序发布方式,但它能经久不衰、肯定也有自己的独到之处。
我刚开始使用 Java 那会,它的初始 GUI 工具包 AWT(Abstract Windowing Toolkit)已经有点过时了,倒是新的“轻量级”工具包 Swing 得到了人们的青睐。简单来讲,AWT 属于“重量级”工具包,提供的是 用于处理本机小部件的 API。重量级 UI 库的问题在于难以维护,而且受到底层平台可用组件的限制。相比之下,Swing 则拥有轻量化优势,能够绘制自己的一组小部件、降低了维护难度,帮助用户轻松绘制出自己的跨平台界面。
Swing 提供可插入 UI,支持样式设置以模拟本机平台的外观。所以在 Mac 上运行时,Swing UI 的观感与 Cocoa 等本机应用程序完全相同;而在 Windows 上运行时,观感又高度接近 Windows。此外,Swing 还允许自定义外观,让程序的使用体验脱离任何操作系统平台。总之,这是一款灵活的 UI 解决方案。
但在 2000 年初的计算机上,Swing 界面也是出了名的资源杀手。我自己有一台半透明蓝色的 iMac,它搭载的 233 MHz 芯片几乎运行不了 NetBeans。我爸爸的 G4 电脑搭载 400 MHz 处理器,性能倒是更强一些,但整个运行体验仍然勉勉强强、凑凑合合。
所以在当时,用 Java 构建 GUI 要求人们对摩尔定律抱有极大的信心——虽然当下的运行表现不好,但再过几年应该会有起色。
时间来到 2002 年,一天室友向我推荐了 Eclipse 与 SWT——这是一套似乎能够解决性能问题的 Java GUI 开发替代方案。Eclipse 使用的是 SWT(Standard Widget Toolkit),一款新的“重量级”Java UI 工具包,但响应速度明显要比使用 Swing 进行构建的 NetBeans 更快。所以乍看之下,长久的难题似乎终于有了答案。
SWT 的优势在于无需自行绘制小部件,而仅仅是为了平台的本机小部件提供绑定,因此由它构建的应用程序在观感上原生度更高、响应速度也更快。但经历过 AWT 的糟糕体验,我仍然保持着警惕。既然 Sun 公司的聪明人都觉得轻量化才是正确的道路,为什么 IBM 这边拿出的是重量级工具包呢?
而且我对 SWT 的兴奋也没持续多久。Eclipse 虽然比 NetBeans 响应更快,但用起来仍然有种笨拙的感觉,完全达不到本机应用的水平。倒是 Swing,虽然速度还是更慢,但一直随着新版本的发布而不断改善。根据 AWT 与 Swing 相关书籍、论坛和博文的数量,我估计 Swing 社区的规模比 SWT 大得多。Swing/AWT 曾经是、现在也仍然是 Java 中内置的唯一工具包,能够确保开发者无需任何第三方依赖项、单凭 Java 运行时环境就构建起完整的 GUI 应用程序。
虽然我还没有在项目中实际使用过 SWT,但很高兴看到它能经受住这么多年的风雨考验。期间先后出现过不少不支持 Swing 的 JVM(Avian 就是其中一种精简型 AOT(预先)编译器,它不支持 Swing、但提供使用 SWT 的 GUI 演示),靠的就是 SWT 这个能在 Java 平台上快速编写 GUI 应用程序的解决方案。
据我所知,2000 年初那会的跨平台 Java GUI 开发市场就是由 AWT、Swing 和 SWT 这三家主导。Java FX 直到 2007 年才出现。
还是在 2000 年初,苹果突然宣布要把 Java 作为 Mac OS X 上的首选编程语言。Java 被预装在 OS X 当中,Swing 也获得了本机 Mac 主题,使其观感高度接近于本机应用程序。这意味着大家完全可以将 Java 应用程序直接发布给 Mac 用户,代码一定能在机器上运行起来、而且提供与本机系统相匹配的观感体验。
他们还推出能将 Java 应用程序打包成本机 OS X.app 的工具,所以开发者就能把 Java 应用程序像真正的本机应用那样交付给用户。如果认真遵循 Mac 用户界面指南,使用者甚至感受不到这款应用程序是用 Java 编写的。
遗憾的是,大多数 Swing 应用程序的开发者并没有遵循 Mac UI 指南,所以用户在使用 Java 应用程序还是能感觉到事情“不太对劲”。比如应用程序可能在菜单项中使用了错误的加速键、甚至不提供标准菜单。没错,虽然听起来很简单,但想让 Swing UI 在 Mac 上完全适配本机风格还是颇有难度。这里我们用 Mac UI 的本机工具包 Cocoa 来对比:Cocoa 提供的是完全原生的应用程序外壳,并且以菜单为起点;但 Swing 应用程序则是从零开始。开发者必须自行创建窗口和菜单,除非直接套用框架——但我从没见过能纯原生 Mac 应用程序体验的 Java 框架。
但苹果总有办法,他们更进一步、为 Coca 提供了 Java 绑定包。如此一来,我们的 Java 应用程序不仅看起来更像是本机应用程序,实际上也成了本机应用程序。我们只需要在 Xcode 中创建一个新的 Cocoa 项目,再选择 Java 作为项目语言即可。它会为大家提供漂亮的本机应用程序外壳作为设计起点,而在按下“Build”键时,生成的将是一个可以直接发送给用户的纯本机应用程序。
我也用 Cocoa 试着编写过示例应用程序,效果非常完美。但即便表现出色,它在行业中也仍然不受待见。因为这类应用程序只适用于 Mac,毕竟用的是 Mac 上的专有 UI,所以 Java 社区里“一次编写、随处运行(WORA)”的狂热支持者们对 Cocoa 嗤之以鼻。另一方面,“原生”Mac 开发社区则对 Java 不感兴趣,所以相关文档很少。而且要实现从 Cocoa 到 Java 的对接,开发者必须能熟练地将 Objective-C 代码转换成 Java 中的等价表示——相当累人。
所以不出所料,苹果在几年之后的 2005 年就放弃了 Cocoa-Java 项目。而且出于种种原因,苹果对 Java 的兴趣也很快淡去。我记得当时史蒂夫·乔布斯还有句名言,“Java 如同开发者的镣铐”。他说得一点儿没错。
如果大家也想试试用 Java 编写 Cocoa 应用程序,请关注Rococoa项目。作为 Cocoa-Java 理想的继任者,它目前仍处于活跃状态。
我的这份“编年史”既不全面、也不完全遵照时间顺序。我讲述的是自己在 Java 桌面环境上的真实经历,而且主要偏向 Mac 一侧(因为家里的第一台计算机是苹果 IIGS,我爸后来又买了台 Mac Classic)。
所以结合个人经历,2005 年可以说是 Java 语言在桌面环境中的发展转折点。在 2005 年之前,网络论坛上有着大量关于 Java 桌面技术的问答内容,例如 Swing、Cocoa Bridge 等。但到 2005 年之后,相关内容快速减少。那 2005 年前后到底发生了什么重大转变?Java 桌面开发者们又跑到哪里去了?我猜大部分开发者可能转向了服务器端,而继续坚守客户端的开发者也许是转向了 Web 或者本地开发方面。
如果您也经历过这段历史,不妨在评论中聊聊自己的体会和回忆。也许拥有不同背景、不同职业生涯的开发者会有不一样的观察角度。
原文链接:
https://jdeploy.substack.com/p/the-decline-and-fall-of-java-on-the?s=r
领取专属 10元无门槛券
私享最新 技术干货