CC++ vs. Java

    技术2022-05-11  133

     

     

    C++ vs. Java

    jy说: 真正的程序员今天(公元2001年)应该对JAVA嗤之以鼻。 真正的程序员是C++程序员。 真正的学者是古PASCAL程序员(注意不要和今天的PASCAL搭上关系,另文备述)

     

    客观的看,应用面的不同,本应导致本文不必存在,两者不是同一层次,并无可比性。然而出于种种个人或者自私的原因,JAVA被一些人不正当的宣传,被作为一种攻击的工具。因此,我不得不浩叹人心不古。

    ---- 包容能力 ----

    象C++/C这样的能够适应多种方面需求的编程语言,时至今日,仅此一家。 从目前看来,乃至可预见的将来,JAVA不可能做到如此的适应能力。

    ---- 灵活性 ----

    模板

    C++的模板,是整个C++发展史上的第二转折点(提出C++第一了)。这为你提供了广阔的发展空间,更加有利与代码的复用。从这个角度来看JAVA的那些可怜的多态,继承,其实仅仅是照搬C++刚发布时的早期成果,有什么好值得骄傲的? 自然,模板比类还要难于理解,以至于看懂STL源码都成了不少初学者认为理所当然的想要跨过的龙门了。

    硬件能力

    不必太深层的硬件操纵能力,仅仅是打开MODEM,设置一个自动应答的铃声次数,JAVA程序员将会抓耳挠腮不知如何是好。 所以,片面的看待JAVA的简单,把简易当作是容易,是大错特错的。

    ---- 基本语法的疑问 ----

    ---- 类体系的疑问 ----

    JAVA引用了Smalltalk的体系,整个类树都是从Object元对象生长出来的; C++则与此不同,你可以拥有任意多个基本元对象,并据此构造出n颗类树出来。 正确的看法是两者各有利弊,无所谓谁是最优的。但是JAVA支持者则强调同源而出的种种好处,引发的论战后果是C++支持者们又论述多颗树的好处。 我以为,这就是JAVA的好处了:引发这些讨论,是可以让理论被深入化的。

    ---- 虚构造的疑问 ----

    JAVA似乎发展出了多态构造函数的语法。如果确实如此,我需要认真想想尚在构造期间的对象是否应该多态。 为了书写这个小标题,我进一步查学了有关的内容。原来,JAVA还是照搬了旧有的规矩,禁止构造函数的多态。 取而代之的,利用RTTI机制,JAVA能实现一种“虚构造”函数机制,基本上是利用类中的main()入口点来完成的。 谈及这里,我顺便以为,一个类中两个孑然不同的入口点(常规构造和main),实在是JAVA的败笔。即便是为了实现特别算法,也不应该推广出类中的main入口点。这让人无所适从。

    ---- 类查找的疑问 ----

    JAVA的类名查找算法是让训练有素的智者也为之奈何的选择。 不必提及初学者的“java.lang.NoClassDefFoundError:”问题了。 即使是老手,也会被莫名其妙的类名隐藏弄到不知所措,而且难于定位故障之所在。 此外,SUN推荐你打包自己的package使用倒序域名的手段,理由是域名是官方唯一的。 可惜在今天域名交换和纠纷频繁的情况下,这不见得是一种好选择。 由于域名的混乱性,中国人也许又该问一句,我使用中文域名的话,我的package又该怎办?可以使用"中国.王中华.util.Vector"这样的名字么? 这一点,即使C++也被VB比了下去。VB(VBA)可以使用全中文的变量名、函数名等等标识符命名法则!

    ---- 继承嵌套类的疑问 ----

    先看这个实例: class Outer { class Inner{} } class ChildOfInner extends Outer.Inner { ChildOfInner(){(new Outer()).super();} }你有什么感觉?我是真的难以理解,这种语法破坏了嵌套类的基本规则:为了隐藏一个局部特性的对象,我们将一个类声明为Outer类的内里。 作为嵌套类,正是因为除了Outer之外,不属于其他任何人,所以才会被隐藏在Outer之中。反之,依照上述的例子,ChildOfInner从Outer.Inner派生出来,意欲何为呢?为Outer.Inner扩充接口?似乎也不可能吧。 是的,这是JAVA 2的SDK文档中的例子,本意欲说明超类的显示构造调用法则。 却不料成了我用来质疑的范本。 话说回来,这也并非只是JAVA的过错。同样的问题在C++中照样存在: class Outer { public: Outer(){ _tprintf("Outer()/n"); } class Inner{ public: Inner(){ _tprintf("Inner()/n"); } }; Inner inner; }; class ChildOfInner:public Outer::Inner { public: ChildOfInner(){ _tprintf("ChildOfInner()/n"); } };我只好说,语法允许这样子做,但这样做是不明智的:需要派生嵌套类的子类的情况,百年也不会出现一次。 JAVA这次被我揪出来当了靶子罢了。 看看,JAVA的语法在做了那么多的限制之后,却反而在这里网开一面,让这种语法得以生存。这不是也挺奇怪的吗?

    ---- 指针 ----

    指针真的惹祸吗?

    是的,指针真是害人精。一个资深的C++程序员,也决不敢说自己对于指针的运用已经无懈可击了。 从C开始,让人千转百徊的,还是指针。 从指针申发开去,多少精巧而简明的算法就此诞生。并且从此以往,给计算机历史带来了多少的生机。 如果指针惹祸,不知今天所有的各式各样的操作系统该做何解?不要忘了可以武断一句,现今运行的OS们, 100%都是C或C++加上ASM写就的。

    用不好指针的人怎能责怪C++不好?

    不要求你使用指针毫不出错。但是,运用不好一种语言的机制和特色,怎能反而责怪这种语言不好? 因为运用不好指针,从而责怪这种语言总是造成内存泄漏,这种逻辑是极为荒唐的。 从另外一个方面来看,同样是一种C++,你可以有不同的运用方法。精深的程序员可以书写高级指针应用,而刚入门的程序员大可以利用各种成功的类库,尤其是STL来解决常用的例行开发,从而避免无法善用指针而带来的恶果。 所以,技术上的垂髫竟然挑剔技术,通常我们只能一笑置之,他毕竟还不免有点幼稚,看不清全貌是可以被接受的。 用不好指针的人是否可以被称为合格的C/C++程序员呢? 我没有确切的答案。

    GC=Garbage Constructor?!

    从GC的表现来看,的确是一种垃圾。 没有节制的吞噬内存,基本上同样是一种失败。 企图指挥GC足够正确的及时回收内存,是一种奢望,因为动态的拣选无用内存的算法,还达不到足够的聪明来保证无用内存能够及时回收。 对于24×7的实时工作,目前的JAVA表现将会不尽人意:你可以通过特别的申明来强制GC启用,然而你仍然无法控制GC指哪打哪,GC会顽固的停滞不前,直到内存终于耗尽时,它还可能并不干任何事儿(JAVA 1.x中,finalize()从未被象JDK文档中宣称的那样工作过,反倒是无计其数的文章指点出不可以依靠 finalize()来完成你可能不得不必须要做的清除动作;JAVA 2中的GC真正的“勉强”符合其文档上的号称了,却更容易造成振荡*)。 *所谓振荡,原是指失败的内存交换算法导致内存临界页面在主存和备用存储之间连续不断的换入换出,而真正需要主存的进程却始终得不到足够的主存的情形。这里是借用此概念来指代无用对象被不断的回收和重新分配,而真正需要的请求反而迟迟不能被满足。 JAVA为了防止不正确使用指针而带来的后果,付出的代价沉重而昂贵。这仿佛20年代的女人袒胸露背一样,过分超前,适得其反。 如果计算机的硬件条件进一步扩展,假定可预见的5年之后,我相信GC付出的代价将不值一提。而作为今天,无论美国,中国,世界,都还是小公司多数的情况下,你难道能要求他们都买下RS6000? 从这一点看,SUN是在迎合巨型公司的口味,却又要立下牌坊,就不免有点那个了。 (IBM全面迁移到JAVA上不让我惊奇,如果他不,我才惊奇:IBM的桌面应用从来都是相对的弱项,提及IBM,大概没人不知道蓝色的后文是什么。对的,“巨人”。“巨人”在巨型机方面配搭JAVA,那才是绝配。可怜我只有一颗266的芯。) 于是,有人换了角度,问我跨平台的问题。

    ---- 跨平台 ----

    当90%的桌面使用Windows的时候,跨平台真的很重要吗?

    我不想在这里讨论MS公司的问题,那是另一篇文章的内容。或者,为防止这个话题被无限展开,主题流失,我应该拿掉Windows的字样,改成MAC OS或者Solaris,怎么样? 90%的桌面使用Windows的时候,SUN是不太高兴的,要谈跨平台; 那么,当90%的桌面都使用Solaris的时候,SUN自然笑开了花。 但是,那时候,跨平台还有多大意义?猜测一下,那时候SUN还会跟你谈跨平台么?善良的人们啊! 再来看跨平台的能力,

    JAVA就是独此一家?

    不是的,C和C++都具备这样的可移植性。真正的程序员随手一抓,诸如PHP、APACHE等等,都是工作在多种平台下的源码。 不错,C++要想跨平台并且基本不修改源码,是不可能的,同时作为一种高级编程能力,大半的“C++程序员”都还不能完成这项任务。这里既有历史因素,又有客观原因。C++的实现版本实在过分的多了,为了给予程序员更灵活操作硬件的能力,各种编译器的自定义扩展也各执一词,这是当前C++源码想要跨平台工作的难点。 反观JAVA,作为寡头统治,号称一次编写,其实是一种未成气候的独裁罢了。今日的JAVA编译器实现,也已经有了若干版本。诚如我们猜测的一般,版本多起来,跨平台也就弱下去。 还不必提起唯SUN独尊时直至现在,JAVA也根本没有确切的达成一次编写的目标。 不论怎么看,这种一次编写都更像一种笑谈,一个迎合部分人心的广告术,一个金玉其外的幌子,败絮其中。 达不到的目标,不要用来欺瞒他人,这种机巧只是违法和不道德的,不是其他的什么。

    ---- GUI ----

    不想多提,反正JAVA弄出来的界面总是那么的难看。 这不是习惯的问题,而是JAVA设计人员漠视GUI设计和人性化的结果。同时,当然这也是JAVA不够成熟的必然结果。 例如快捷键的设计,默认按钮,焦点切换等设计,例如色彩搭配,例如工作空间布局和占用的问题,从 Swing开始就失败,所以基于JAVA基础搭建的应用程序几乎统统都有非常可怜而不友好的界面,粗糙而简陋。 哪怕是JBuilder这样的重磅型产品都不能让人足够满意。

    ---- JAVA之得意之笔 ----

    JAVA的得意之笔还是极其的多的,我只列出下面三条,更多的不再罗列了,这篇文章并不打算成为论文的。

    数组

    JAVA最值得被称道的,或许应该是返回数组的功能。不要考虑JAVA是怎样实现的,仅仅观看这一能力:C++中返回数组会带来相当多的生存期问题,为了防止弊端,可能不得不强问题复杂化。 JAVA的这一能力使得程序员能够更为自由的运用特别方便的算法,实在功不可没。

    GC

    前面提及GC的弱点,但那并不是我们的唯一观点。作为一种机制,GC是具有前瞻性的一大提高,这从现在的新鲜出炉的各种东西都不约而同的提供GC机制就可见一斑。由于GC的存在,程序员可以放弃对更多细节的关照,从而把精力放在对商业逻辑的设计上,这是GC的绝对贡献。 (自然,前文表述了我的个人观点:GC是先进的,但也是青涩的,现在就吃,会掉牙的。我自认能够很好操作指针,所以这是个人观点,不想妄求赞同了。)

    体系

    前面没有提及半点有关体系结构的文字。这是因为C++本身作为编程语言,并不涉及到系统设计方面的问题,但JAVA的完整内涵,却包括了大量的“固定且公认”的设计规范和体系结构。 对于一个典型的商业应用,利用AppServer提供底层框架支撑,JDBC提供异质数据源的接入,各种工作流服务随时就绪;JNDI提供统一规格的命名式通用访问;等等等等。这些,为开发打下了良好的基础。 自然,传统看来,这并不属于编程语言应该关照的内容,我也不再过多讨论。 作为一个完整的解决方案和体系,这是JAVA独有的优势。也是它的强势之处。 作为JAVA的方便性和强大,例子还很多。请注意我们的立场:作为晚于C++这么多年之后,并且参考C++ 的各种优点之后推出的新的语言,如此“多”的强大却也还是不免太少。

    ---- 初学者的误区 ----

    “真的一次编写就足够了”。那样,能完成的任务可能会太玩具,没有多少使用价值。注意:不要片面理解这句话的含义,也不要把广告辞当作是真实世界。 “没有的指针,就不会犯错了”。哪里的话!还是有大量的事情需要你去担忧:需求采集足够和准确吗?还能适应今后的足够长的需求增长吗?体系结构设计合理吗?类的设计和选择够弹性吗?算法选择适当吗?分支逻辑正确吗?成员还没有初始化?是不是还没有连接网络?是不是没有考虑校验用户的非法数据?磁盘空间不够了怎么办?设计文档符合你的代码吗?你的代码符合设计文档的要求吗?能够在窗口(表单)上摆布两个控件,并不是程序员,更不要提是不是真正的程序员,这只是末流而已。 “人人都能编程”。最大的谎言,这个梦想永远不能实现:技术进步的同时,对人的要求也在进步。昔日诸葛能看天气是为诸葛;今天任何人收听电台电视上网都能知道天气,并不代表人人都是诸葛了。 “JAVA简便易学”。为什么人人都愿意相信谎言而不正视事实呢?这和C++简便易学、VB简便易学一样,都是古怪的。总是有人妄想不作付出,而有收获。可叹! “国外公司都使用JAVA进行开发”。是吗?几百万的VB程序员们啊,站出来让伊们看看。然后,我们再来考量一番全球能有多少的职业程序员,比较比较JAVA程序员的真实数量,可好?事实是,且不论开发的人数和质量,只管聚焦这样的真实:国外也不过是有名有姓的极少数公司已经足够成熟的使用了 JAVA来构建自己的整个企业信息化平台。初一看这倒也不可思议,其实也挺正常,历史和性能,还有成熟度等等的原因。并不是有几百万个程序代码的片断就代表了语言的好坏,企业计算需要考虑的问题并非这么的轻率的。 全球500强的工作模式适应你的公司的环境吗?因为500强中的几家或者几十家使用JAVA系统,因此你的公司也应该使用JAVA系统? “能做出来就好”。我很不以为然,持这种态度的人,将会被我骂死。我没有什么民族产业那么的高度,却讨厌这种不负责任的态度。所以,中国大陆的开发总是恶性循环,没有质量,进而没有进度;没有进度和质量,于是没有订单;没有订单,好不容易居然有了,于是进一步的要求,赶紧搞出来吧,谁叫咱没有效率呢;于是再度没有质量和进度。最后,没有象话的东西示人。这时候,个人力量已经微不足道了,只好任由一步一步的衰败下去吧。

    ---- 结束 ----

    JAVA的路还很长。

    要想真正具备实力,JAVA还有很长的路要走。JAVA仍是一种不成熟的规范。简单列举一个例子:嵌套类是一种有用的模型,JAVA生产的嵌套类总是OuterClass$InnerClass这种命名方式,注意到这在相当多的UNIX平台中会有问题,因为UNIX通常使用$符号作为命令行提示符。 Solaris本身就是UNIX的变种,而SUN居然遗留这种问题,不能不让人怀疑其素质或者敬业心等等。(现在不必担心名字与提示符冲突的问题了,今天这已经不是问题)再如:请参阅Thinking In Java一书第六章关于final处的论述,那里精辟的反驳了JDK 1.x中令 Vector不能被用户复用的不足。注意到JAVA 2中这一不足已经被调整了。在会心一笑的同时,你应该充分正确而完整的认识到JAVA的不成熟。SUN并不打算保护你在早期JDK开发方面的投资,重要的是,SUN的投资和那几十(?)位Java、 JDK的设计者的偏好更为重要。而当时的JDK和现在的JDK,也许可以不过分的称一句已经翻天复地的变化了,若干早期代码在不算久的今天已经有了“标准”的实现。一个小小的例子是generic,让众多的支持者们热切期待JAVA版本的模板机制能被实现。这些支持者等到了 JAVA 2,却发觉没有generic关键字的踪影了。可以预期,对此,SUN会说模板将事情复杂化了,所以不计划支持这种不简易的东西。这和MS不同,MS并不是C++的负责人,而MS这么多年以来,在自身产品的兼容性方面承受了相当多的代价。更何况SUN的文档要和MS相比较的话,简直提鞋都不够。JAVA的STL的更优秀的版本不是由SUN生产的,JAVA文档的索引还是JBuilder之类提供了真正的检索和目录。对于我个人而言,刚开始做JAVA的各种软件包的配置简直是恶梦,看看已经毫无差错了,偏偏还是找不到类,如今回首,当然可笑了,但这样可不叫易用。SUN可能应该反省一下自己究竟够不够资格做JAVA的监护人。你已经知道JAVA在企图面面俱到,处处都有 JAVA的身影,也处处都遗留问题。而SUN真的独力足以支撑么?还是死抱着许可证不放,有什么开放可言?这就是司马昭之心了。我才不介意SUN有没有野心呢,我只想怀疑SUN这个至今仍靠硬件产品为生的公司,有没有那么强大的实力来完成JAVA一统天下的夙愿。而进一步的,真的一统天下,是福兮祸兮?SUN能够就此千秋万载?对于一个发展中的规范(JAVA已经不仅仅是一种编程语言了),我在前文中不留情面的偏激地进行了斥责。我真的要向你强调,在盲从JAVA前,还是应该细细考量。JAVA中还太多BUG,偏爱它的人往往并不正视这些问题,作为严谨的程序员来讲,这是令人失望的。JAVA给我们带来了小部分技术的前瞻,尽管略为超前,却是可贵的。然而,站在前人的经验之上,仅仅如此之少的改进,还是让人不能满足。SUN公司只是不成功的枭雄,在商业上的不成功之处也怪多的,何况早有迹象显示出它的野心勃勃。从这个意义上,争论JAVA是否优秀还是比较浪费的。甚至夸张一点,JAVA前景堪忧。天下大势,分久必合、合久必分。JAVA要想保持Pure,本身就是违背规则的。而一旦不能保持,百花齐放之下,今天JAVA吸引眼球的众多特色将会损失殆尽。

    ---- 再论垄断 ----

    很多方面的经验告诉我们,唯一化的选择只能由集中强权才能保证,是为垄断。 象一次编写,唯一规范等等,都有这样的背后不为人注意的空白之处。细细思量之余,当可发现,午餐晚餐都不会免费的。

    ---- jy附言 ----

    为了可比,本文只侧重考虑两者作为编程语言方面地一些局部状况,见解不高竿,自然毫不意外。 这方面地讨论已经很多版本了,我并未提出什么特别独有的思想出来,也不必对我有此奢望。 前一段时间因为爱好和需要,转入JAVA中学习,一方面是不信邪,我咋的就学不会那;一方面还是不信邪,JAVA这么好,真的能让人象大跃进一般。于是,这篇不过是学习笔记的感想就出笼了。 由于其实是笔记,语气不免尖刻一点,算是我的坏德行好了。 最后,感谢你阅读此文,浪费您的时间真是遗憾。

    最新回复(0)