java无用论
2000-10-24
1. 写这篇文章的目的
学了一些关于java的东西,个人认为它很不好用。为了减少上当人数
特写此文。
尽管 java 宣称它是100%面向对象,而c++不是。但是宣称100%面向
对象本身就不是什么面向对象的思想。面向对象的本质目的是提高生
产率。讨论一种语言是否100%面向对象就好像讨论我们的社会性资性
社一样滑稽。其实学习面向对象不一定非要使用java不可。我反而认
为120%面向对象的c++是不错的选择。
java号称跨平台,其实这是只一个梦想,也不妨用骗局这个词来形容
。软件的移植性仅仅和虚机相关吗?照此理论是不是可以说符合ia32
体系的软件在任何ia32体系上都能正常运行。那我怎么没看见sco:
:lf 在 nt上运行?显然,除了虚机,软件二进制规范(执行文件格
式、连接方法)、运行时间库和系统调用也是软件移植问题因素。而
java规范中显然不包括完整的运行时间库和系统调用,甚至二进制规
范也有不兼容的地方(比如本原接口和固有接口)。软件总不能脱离
它的运行环境,不兼容就从这里开始。
要提高软件生产效率。应当认认真真的研究系统结构、二进制规范、
系统调用结构才是解决问题的方法。靠概念游戏这种投机取巧的方法
是行不通的。
我说java不好,甚至不必对其侧目,你信吗?我估计信的人不多。我
只是想说“上当之后别怪我没说”。
另外如果您在java中发现了甜头也不妨告诉我。互相学习吗:)。
2. java究竟是什么?
java是一种虚拟硬件系统结构,是一种软件二进制规范,是一种编程
语言。当我们看到java一词时,它可能表达上述三个含义钟的任何一
个。尽管这三个东西可以独立存在,不过实际上他们总是在一起出现
。所以也很少有人分的那么明确。使用fortran语言编写java虚机上
的代码理论上是可行的。但是有谁乐意做这件事呢?
作为虚拟硬件体系结构,
java虚机和alpha、powerpc、sparc、ia32、51、960是同一概念上的
东西。也许您会奇怪?他们怎是同样的东西呢?ia32不就是piii、pi
v那一大块吗?其实不然、我们知道386、p5、p6、p7的内部结构非常
不同。属不同的微体系。但是他们实现了相同的ia32指令集合。ia32
也不一定非要通过硬件实现,通过软件也可以。这种软件cpu产品广
泛出现在操作系统和cpu密集软件的开发、调试工具上。主要用于在c
pu出现之前调试软件。java指令集同样也可以通过硬件实现。只是在
半导体工业激烈竞争的时代,没有大公司(含sun)愿意把这么做。
sun常常说m$很害怕java。他们之间的确存在很强的竞争关系。倒不
是java高级语言的问题,我认为是java二进制规范和 windows操作系
统存在竞争。不妨考察java中的(.class文件格式、装入方法、执行
过程、jdbc接口、j3d接口)和windows中的(pe文件格式、dll文件格
式、装入、连接方法、odbc、direct3d)。就知道竞争多么强烈。和n
t/ia不同。java.exe执行程序包含虚机规范和二进制规范。在nt/ia
中是分离的产品。
人们总喜欢把java高级语言和c++类比,他们之间的确存在很过相似
的地方。不过我认为c++和java不存在什么竞争。它们使用在不同的
场合。他们的区别(内存管理、对象类型、线程规范)决定他们的用
途。用形似而神不似来形容c++和java吧。仅从高级语言方面来看。j
ava真正竞争来自ecmascript 。也就是jscript和vbscript。
3. java虚机和ia32比较
java vm和ia32最大的区别是java vm的主要实现不考虑效率问题。由
此派生出寄存器少,指令结构简单(同样功能生成的程序代码长),
寻址空间小,寻址方法少、数据类型少等。除了上述问题,java vm
没有涉及指令(显式或隐式)并行问题。
3.1. 基本特性差别
3.1.1. 数据类型比较
java vm
ia32
整数类型
byte
short(16bit) char(unioncode)
int
long (64bit)
{不存在无符号算术运算指令,另外注意这里没有boolean类型}
byte
word(16bit)
doubleword(32bit)
quotaword(64bit)
doublequotaword(2*64bit)
bcd/packedbcd
bitfield
{存在有符号和无符号两种运算指令}
浮点类型
float(32bit)
double(64bit)
float(32bit)
double(64bit)
long double(80bit)
packed double(2*64bit)
地址
returnaddress*
8bit , 16bit , 32bit , 48bit都有
没有显示的看到returnaddress
类型的宽度,不过。通过指令goto(0xa7)和goto_w(0xc8)来看。retu
rnaddress是可以是16位或32位的。
关于double和long的原子问题:在目前的java规范中,double和long
作为两个独立的32 位数据独立存取。这样可能产生同步问题。历史
上intel的cmpxchg8b(pentum pro以上cpu提供)指令就存在过类似
问题,一度被指责是cpu设计问题。好在cmpxchg8b很少使用,没有造
成什么事故。
3.1.2. 指令集
指令类型
javavm
ia32
load/store
1) 数据和运算栈之间单个移动
2) 常数移入运算栈
1) move
2) cmovexx
3) 交换,琐操作
4) push/pop
5) pusha/popa
6) in/out
元算指令
add , sub , mul , div , neg , rem , shl , or , and , xor
比java多多了,主要多在显式并行上
类型转换
基本类型之间可以互相转换
有(由于类型很多,转换指令也有很多)
方法调用
4条指令
一大堆,主要多在权限切换(调用门)、长短跳传不同上。
3.1.3. 异常
虽然javavm有异常的支持,不过很简单。它不区分中断、陷阱和故障
。也不能明确指出出错代码的pc,并返回那里重新执行。
3.1.4. 执行态
java vm没有用户态和系统态执行区分。当然也没有mmu(管理内存分
页、分段的内存管理单元).除非被java高级语言限制,java vm汇编
代码也能完成一些恶意操作。
3.1.5. 小结
总而言之,java vm很简单。sun总是认为通过编译优化java可以达到
c++速度。显然是谎言。如果要编译成本地代码,显然要丢失移植性
。如果不编译成本地代码,效率问题如何解决?有一种及时编译的设
计。对于很小的应用也许可行。对于规模的应用呢?要知道优化编译
很费cpu和内存。像ia64体系的优化方案,要编译很多遍才能优化完
成。要运行时刻编译是不是天方夜谭。
4. java高级语言和c++、jscript比较
4.1. 效率,谎言
很多书上写java是很快的语言。这时一定要看清楚是比谁快。语句传
了几本书难免有些误差,比较对象经常有意无意丢失。一般认为java
比jscript快。的确快很多,不只十倍。我也承认java比jscript快。
但有人说java和c++效率接近。这就是骗人了。他们也能做出试验证
明,试验结果好像也能证明结论。他们的实验大概都是形如这样。
java, c++测试代码:
for ( i = 0 ; i<100 ; i++ )
{
remotecall( i ); //外部调用,调用一次用1s。
}
结果:
java 102s , c++ 100s。
结论:
java达到了c++ 98.0%的效率。
这种测试违背了测量学中要把测试对象放到主要矛盾上这一基本原
理。方法的不正确当然带来了测试结果的不正确。有本事比比
for ( i = 0 ; i<10000; i++)
{
y = x * z; //由java语言或c++语言实现执行体
}
我的结果是170倍。也就是piii变成了286。如果使用指令并行优化
,c++和java的速度差异可以达到千倍以上。想用一下8088吗?
4.2. 功能缺失导致代码膨胀
简单的说,java比c++缺少编译预处理、缺少运算符重载、多继承和
类模板。我认为取消这些概念很粗暴。和c++不同。对于大规模编程
来说,java的代码量不会比c少多少。甚至由于类型约束太强。有可
能比c的代码量还大。
java常称多继承比较困难,所以要取消。而且使用实现接口的方法可
以代替c++的多继承。但是,实现接口要自己写所有的接口实现代码
。不嫌烦就慢慢写吧。
为什么要取消运算符重载?真是不可理解,既简单又好用。它居然说
难,且容易造成混乱。
总之,处理这几个大方向的问题,还有很多小问题。据说awt不好用,
感觉他们为了完成任务写程序。
4.3. 简单的骗局
自古便宜没好货。java总是宣扬java如何简单,主要宣扬的好处是垃
圾自动收集和线程同步。其实不然,由于java没有释放关键字。使得
不能及时释放或定时释放不必的数据。要知道能够分配的不只是内存
,还有数据库句柄、文件句柄、结果集等。这样不得不绕来绕去的完
成这些任务。其实c++的析构函数是自动调用的,也不用自己手动掉
用。遇到一些特殊情况,c++也能很好的解决。
也许java的线程比较简单吧,不过c++中也可以继承线程类。由于本
人没有涉及线程编程。这里不好乱说。
5. java的兼容性
相对本地代码来说,java程序的确移植性比较好。归其原因不外有二
。一来java虚机只一种(不像天下有很多种cpu),二来java二进制
规范只有一种(不像这么多种操作系统)。但是,java代码真的可以随
心所欲的移植吗?其实不然,上述两条中的任何一种不再满足,都会
影响bytecode的移植性。
现在,java的主要版本已经有1.0 , 1.1.7 , 1.2(2.0)三个。更残酷
的是1.1.7和1.2不兼容。一个很著名的例子。websphere不能在java1
.2上运行。另外weblogic不能在1.0上运行。
java的二进制规范呢?jview( ms java)就自立门户。他的.class装
入方法就和java for win32不同。另外它提出了其他的本地代码连接
方法。显然这里也会造成不兼容。
除了上述两条重要的原因,还有就是程序的运行环境。比如操作系统
是否区分文件名的大小写。数据库是否中调用都能返回执行成功。ej
b的代码是否有ejb 的运行服务器。等等。
6. 在精通java之前否定java
本人只是对java略知一二。为什么就非要否定java呢。其实,从一般
科学观点审视java。就会发现其中的问题。
6.1. java代码不符合从简单到复杂的认识规律
代码比较:
java code example:
import java.applet.*;
import java.awt.gaphics;
public class helloworldapplet extends java.applet.appple
{
public void init(){
resize( 200 , 150 );
}
public void paint( graphics g){
g.drawstring("hello world" , 50 , 100);
}
}
c++ code example:
#include
class hello :public applet
{
public void init();
public void paint(graphics g);
};
hello::init()
{
resize( 200 , 150 );
}
……
我们看到,java开始就要求写函数的实现。而c++先要描述轮廓。再
写函数实现。
6.2. java对从一般到特殊的思维方法支持的不好
从一般到特殊,是重要的思维方法。对应到计算机学科就是继承。而
今多继承的概念已经广为流传。比如我们说“小花猫”,就是继承“
小”、“花”、“猫”三个概念。如果在字典上看到小花猫这个词,
它一定不再描述“小”、“花”、“猫”这三个概念,而是继承他们
。但是java只能继承其中的一个。对另外连个还要仔细的描述。写起
来是不是很烦。
6.3. java设计不尊重“任何事物都有产生、发展、消亡的过程”这
一自然规律
java没有析构函数。这一点很讨厌。我只想重复一遍“对象不都在内
存空间中”。
6.4. java 不能表达少数类之间的紧密相关
java要求每个类使用一个文件。这种实现可能和它的自动编译执行方
式有关。注意这种限制不是实现上问题,而是规范中的语句。但是这
种方法合适吗?请看下面c++的例子。将这两个类分开为两个文件是
否真的好读?
struct menuitem{
string strx;
int iindex;
};
class menu{
menuitem item[100];
… …
};
和这种情况类似,javadoc也不能对紧密相关的数据进行描述。
至于类模板。java更是不支持。自己一个一个的慢慢写吧。
6.5. 批判java的批判
java要诞生,必须批判原有c/c++语言的缺陷。列举其中一二。
“c/c++语言中的整形数据不限制长度。这样一来当程序从32位系统
移植到16 位系统时会造成错误”。可是仔细想想。这种移植的概率
究竟有多少?
“java不像c/c++,它完全不支持指针”。按此理论,同样不支持指
针的fortran77和basic是不是也很强壮。
“java不允许隐式类型转换”。如果整形和浮点数据之间的转换都要
写一下,是不是很烦。
“联合体、全局变量他们都不是面向对象的东西”。面向对象一直就
没有什么定义。本着好用的东西就是好东西的原则,保留这些概念也
不错。像m_pi这类的常量或者项目中的确全局相关的准常量,使用全
局变量是不是很方便?至于联合体,是优化存储效率用的,像 java
这种不考虑效率的语言自然不会支持。
“java存在比c++多的运算符”。好像是多一些,他们是(字符串 +),
> >> , (boolean)& and | , instanceof。但是我们分析一下。由
于java不支持运算符重载,只好单独实现(字符串 +)。由于java 不
区分有符号和无符号数据,所以使用>>>来表达无符号右移、由于jav
a中的boolean和整形之间没有联系,又不支持运算符重载,所以对bo
olean类型单独实现& and |。至于instanceof的确是java 独创,不
过这个运算符的用处还要考虑。我在引用某变量时居然能不知道它的
类型?
6.6. 兼容以不兼容为代价
使用java 必须一切从头开始。java不能继承原有的工作。而且它也
不能很好的和其他语言混合编程。这就和c++区别大了。首先c++继承
了大部分c语言代码。其次,c++可以和pascal , fortran , basic,
t-sql等其他语言方便混合。尤其方便的是asm语言和 c++混合。发挥
不同语言的长处。俗话说“朋友多,天地宽”吗。而 java只能孤军
奋战了。
7. 结束语
写这篇文章用了一天半的时间。又在java上花了这么多时间,真是心
痛。但愿有些效果。
7/7
