关于作者

姓名:Kiash

性别:男

出生日期:1983-07-04

地区:上海-浦东

联系电话:

QQ:122779601婚否:未婚
用户名:kia126
笔名:Kiash
地区: 上海-浦东
行业:其他

日历  

快速登录

+ 用户名:
+ 密 码:

在线留言



Google Search

Google

WWW 祺亚西

访问统计:
文章个数:23
评论个数:5
留言条数:12




Powered by BlogDriver 2.1

祺亚西

 

文章

上海,今夜请将我埋葬
            如果你是一个踌躇满志的男人,在事业上却毫无建树而又收入平平,那么还是趁早离开上海吧,否则多年以后,你一无所有,只会成了这个城市的殉葬品。这座城市在吸干`你满腔的热血之后会无情地将你唾弃,它得到的是繁华,你逝去的是青春。
    如果你是风姿绰约的女人,却还没有找到自己想要的归属,还是趁早离开上海吧,陆家嘴的摩天大厦承载不了你的梦想,徐家汇的繁华市井给不了你幸福的生活。这座城市在蹂躏了你原本纯洁的肉身之后会一脚将你踢开,它得到的是快感,你破灭的是梦想。
    
    离乡背井、妻离子散的人们啊,你们来到上海这座城市是为了赶时髦还是为了过日子?是为了创业还是为了恋爱?是为了赚大钱还是为了学文化?你们得到了什么又失去了什么?
    上海,不是一个恋爱的城市也不是一个生活的城市,是充满铜臭与肉欲的文化荒漠。这里的物质世界与精神领域到处都遵循了商品经济“等价交换”的原则。穷小伙即便是爱上一位长相普通的女孩也需要太多的理由;所谓的一见钟情只可能发生在你潇洒打开车门的一瞬,所谓的含情脉脉可能出现在你疯狂刷卡大笔一挥之后,一切来得却又是那么地简单,那么地自然。这样的爱情即便是得到了又有几个人会真正地去珍惜。
    
    上海是个喜爱聚会的城市,家人、朋友、同事、网友、同学之间的聚会是常有的事。在上海人看来,如果谁家春节的年夜饭不是在饭店吃的那似乎就不够时尚不够有钱不够体面,早在过年前一两个月各大饭店的年夜饭就早早被预定一空,也许这就是上海人的自尊。我想对于大多数中国人来说,除夕之夜一家人在一起包饺子吃团圆饭是件非常幸福的事情。憨厚质朴的优点在上海这座城市丝毫得不到体现。
    我有生以来第一次参加的“AA制”朋友聚会就是在半年前的上海。在此之前我听说过“AA制”但从未遇到过,以前参加过几次聚会都是在一些中小城市,吃完了总有人主动买了单,很少提“AA制”。记得半年前的那次上海聚会吃的是火锅,8人吃了340元,340除以8除不尽,结果付帐的时候就有人把硬币都掏了出来,有的硬币掉在地上滚了好远,服务员似乎也习惯了这种拼拼凑凑的付款方式,竟然蹲在地上帮着寻找那个滚远了的一元硬币。后来我跟一个朋友说看到这样的场面心理很不舒服,这叫什么吊朋友啊!朋友说在上海就这样,这并不能说明什么,大家都习惯了,没什么不好意思的。后来,因为生活的寂寞我陆续又参加了两次朋友聚会,渐渐地习惯了用总额除以人数然后掏钱的习惯,后来我越来越觉得“AA制”真他吗的好,那么多人吃饭、唱歌、喝茶只花了自己很少的钱。
    上海,难道真的是个省钱的城市吗?
    聚会几次之后,我才发现:聚会确实随时都有,可朋友还是一个没有。
    我也曾经试着单方面掏钱请人出来陪我喝点小酒,可是男人们怀疑我要找他借钱,女人们怀疑我要跟她做爱。所以我到现在还是喜欢一个人喝酒。
    我知道这些男人和女人来上海之前不是这个样子的。一个人,一旦流落到上海,想不变坏都难。
    谈起做爱,我要插几句。
    在上海闯荡的女人,可以假装跟你恋爱,可以勉强陪你做爱,可如果你没有房子,她们坚决不愿做你的太太。
    用我一位四川老哥的话说:上海女人全回锅肉。找老婆不要在上海找。能够独自一人混迹上海并长期生存下来的女人,绝对不是省油的灯。她们可以为帅哥挺“身”而出也可以为金钱奋不顾“身”!

上海是个适合作爱却不适合恋爱的城市。做爱的对象比鸡还多,而恋爱的对象凤毛麟角。如花似玉的女人很多,冰清玉洁女人很少,好不容易在茫茫人海中找了一个值得用一生去爱的女人,爱了大半年以后才发现她竟然还有第二职业。身材魁梧的男人很多,真材实料却很少,扒光了他们的衣服,其实都是软钢筋。对于生活在上海这座城市里的男人们来说,“朋友是用来出卖的女人是用来作爱的”这句话可以作为他们的座右铭。
    女人们找了个穷帅哥做为男朋友,满足了自己的虚荣心却给满足不了自己奢华的物质追求,于是她们千方百计地与有钱男人发生了关系,接着要求他们为自己付掉一年的房租并承诺“提前通知,随到随玩”!她们同时真心地爱着两个男人,失去任何一个,都与心不忍。变态的城市造就了变态的女人,不过我很欣赏这样的变态女人,至少她们是诚实守信的,是遵循商品经济等价交换原则的。
    相形之下我严重鄙视那些骗吃骗喝的女人,她们言而无信、贪得无厌、敲诈勒索样样都来,她们没有上海女人的风尘气质也没有乡下女人的淳朴之美,说她是乡下人她不承认说她是城里人她又老土,根本就“玩不起”!跟本就“不上路”!这样的女人下场最悲惨!
    我那不争气南京老弟在上海也混了一年了,认识了一位稍有几分姿色的女人,此女一口地道的上海话,老弟总是误以为她是上海人,接着就连续请她吃了五顿饭,到第六顿饭的时候他拉了这女人的手,第七顿饭的时候他搂了这女人的腰,从来没有遇到半点反抗。于是他邀请这女人一起到杭州西湖游玩,女人也欣然答应了,晚上开了房间,我那老弟心想终于水到渠成了。结果当他即将插入的时候那女的说:其实我一直把你当朋友,你不能这样对待我。
    我那老弟哭了,说自己已经陷入了爱情的深渊,在他的苦苦哀求之下,这个女人终于答应脱掉衣服让他看个够,但是不准摸。我那老实的老弟真的没摸,他说他看一眼那白皙的身体已经足够。后来如那女人所说,他们真的做了朋友。我老弟过年告诉我,那女的在上海混不下去回老家结婚去了,临走时向他借了500块钱,现在一直联系不上。
    今天我要告诉那些所谓的女性“朋友”:如果真做朋友,那就必须做到物质上和情感上的“AA制”,不要在关键时刻借“朋友”之名来掩饰自己的贪婪,那是在等价交换世界里的不等价交换。“朋友”这两个字是绝对的,是没有双重标准的。
    我早就告诉我老弟,男人跟女人之间无友谊可言,我从来不跟女人做朋友。他总是不信,总是吃亏。活该!
    真正纯洁的女人是不会紧紧捂住自己的裆部跟人谈情说爱的,只有那些逼上起了老茧的女人才夹紧双腿伪装纯洁。跟一个污浊的女人上床需要浪费太多的时间和金钱,要接受太多的质询和考问;跟一个纯情的女人上床是很不经意的事情,所有的感动都被深深地埋藏在心里。
    
    上海,男人不相信女人,女人瞧不起男人,所以这里有着太多的单身男女,当他们征服不了欲望的时候,欲望就将征服她们。于是,酒吧成了他们释放欲望的地方。上海衡山路、茂名南路的酒吧文化充斥着这座城市的性文明。白天,这里沉积了夜晚的尘嚣;夜晚,这里荡漾着白天的幽魂。刺鼻的空气里弥漫着欲望的味道,香烟拌着啤酒来回游荡,震耳欲聋的音乐融化了理性,所有人看上去都象个无家可归的人,扭曲的屁股,摇摆的人头,颤抖的阴茎,跳动的乳房……
    我试着捂住自己的耳朵看这些人,他们就跟木偶一样。
    
    
    我曾以一名平面设计师的身份应邀参加一位海归青年的软件发布会。说是发布会,其实就是在一家四星级饭店的小会议室,大概去了十几个人,看起来我最寒酸,因为我刚从乡下来上海不久,我没有多说话,我很专心听他们在闲聊各自的工作。
    其中一人带着金边眼镜,西服笔挺,皮鞋噌亮,俨然一副学者姿态,高谈阔论。当有人问他的具体工作时,他说:“我是做投资的。”说完并没有展开谈去,就岔上了别的话题。
    还有一个女的,那是相——当——的有气质,头发大波浪染了褐色,穿衣大方得体,硕士学位,标准的上海装束,她说:“我是做EF的。”她这么说的时候将“EF”两个字母的发音咬得很准并且声音很大。没人懂“EF”的具体含义,又怕自己被嘲笑为孤陋寡闻,所以没人问什么叫“EF”,她也没有解释。
    临走的时候,在电梯里,有某人问某人:“你是做什么的?”某人说:“我是做展览的。”海归青年立刻接上话茬说:“他经常去南美与中东,平时很忙的。”
    从我来到这个发布会的现场开始一直到结束,我一直是个听众,我什么话也没说,也没人理我。
    走出电梯,说完再见,各奔东西。我注意到他们当中有人站到了公交站台上,有人步行,有人之前就说“今天下雨,等会叫一辆TAXI”回家,还有一人骑一辆破自行车走了。只有我,是开了公司的Jeep过去的,也许在他们看来,我只是个司机。
    几天后,我从海归青年那里了解到,那个搞投资的是招商银行信用卡部的业务员,平时主要工作就是推销信用卡;那个做“EF”的是做教育培训的,“EF”是“Education Foster”(教育培训)的简称,她在国外呆了几年,回国找不到工作,只能做个英语教师了;那个经常去南美与中东做展览的其实是个带路的,一个到处打游击的线人。而我这个海归青年朋友的软件其实只是个聊天软件。
    那个说叫“TAXI”回家的人我不知道他是做什么的,从他的言谈我看出他为自己会说上几句英文而沾沾自喜,从他的举止我可以看出他认为在上海打“TAXI”是一件很了不起的事情。
    
    
    说起打的,那在上海真是叫遭罪,找一辆的士比找一个厕所要困难得多,而且还要看司机心情好坏,他想停就停,不想停就不停,更有甚者,停下来没等你上车就大声问你到哪儿,如果你去的地方他不喜欢,他就摇摇头一踩油门绝尘而去。遇到这样的主儿,我一般都是先开门,进去坐下来直接告诉他我要到哪儿哪儿,他不去我就跟他发脾气,结果他还是去了。还有司机给我发香烟抽,我说我不抽我希望你也不要抽。他只好不抽。当然这种现象并不普遍。我们经常看到的普遍现象是下班之后马路两旁站满了打车的人,一个个把手伸了出去,就跟乞丐一样,一辆辆的士疾驰而过,就跟飞贼一样,感觉有点象是“十里长街送总理”,只是不太感人而已。我曾经在一个不太繁华的路口等了80分钟,从我眼前经过的100多辆的士竟然全部满载,害得我错过了长途汽车站的最后一班车,在另一个城市滞留了一个晚上,本来当天晚上就可以抵达的目的地,结果第二天才赶到。
    有天晚上,我要在短时间内从火车站赶到上海音乐学院附近吃饭,他们叫我打车过去但我没有,我硬是步行带小跑到了地铁站买了张票2元,乘地铁(好象是一号线)20分钟就到站,出站后花10元叫了一辆“摩的”(摩托车载客)穿梭于大街小巷,他在车水马龙之间游刃有余了约5分钟就把我带到了饭店门口,全程票价12元RMB(比打车便宜了10元)!他们说那么快就到啦?听说高架今天很堵哎。我说我从今以后不会再打的。
    在上海打“TAXI”愚蠢而落泊,破财且误事。尤其是在下班之后晚饭之前,或者天上还下着毛毛细雨,可能还是个周末……如果你们还不知疲倦,那就去为争一辆“TAXI”搞个你死我活吧。
    乘地铁快是快了点,但也不会让你有多舒服。人民广场的地铁让你窒息,熙熙攘攘人头攒动,你分不清谁是流氓谁是窃贼!乘公交最难过,冬天尚可取暖,

再说回家过年,我真为那些家乡远在千里之外的的有痔青年感到悲伤,他们需要提前N天到体育馆排队买票,有人白天没排到,半夜两点再过去排,好不容易买到一张站票要站40个小时才到家,来回的路费也是非常可观的。更有些不幸之人,上了黄牛之当,哭都来不及。一年又一年,就这么忽悠着过。
    
    或者你混得不错,你有车,你庆幸自己再也不用挤公交了。可是你要是敢乱停车,可能出现两种情况:一种情况是你的刮雨器上被夹了罚单,另一种情况是你的车子不翼而飞,在你惶惶报警之后会被告之带200元钱凭相关证件到某交警大队接受处理之后再到某停车场某老大爷那里去取车。
    总之在上海,车子一停就要交钱,停错了多交钱,停对了少交钱。
    用黄油漆在人民的土地上画了几个格子,指挥人民将车子放进格子,然后按10元/小时的价格收取人民的停车费,这不知道算是什么逻辑。我记得小时候老师告诉我们人民才是土地的主人,现在怎么都变了,也许这就是所谓的和谐社会吧。
    
    
    和谐社会里的Supper maket(超市)并不和谐。上海的大小超市我去过大概不下30家,我,张怀旧,今天可以很付责任地告诉全国的电视观众,上海的超市营业员98%是清一色的中年妇女,而且根据她们的表现我可以推断她们多多少少都患有不同程度的“月经不调”。
    大家可以想象在刚刚脱掉贫困帽子但还没有多少文化的中国,处于这个年龄段的女人一但当上了营业员,那对我们消费者是多么的残忍啊!所以我说,上海超市解决了大多数二次更年期妇女的再就业问题,她们下岗之后从新走上工作岗位,有事可做了,在很大程度上缓解了她们的家庭矛盾,但随之而来的是给我们全社会也带来了一定的不和谐因素。
    有次我跟我朋友小卞去一家不大不小的超市买洗发水,找了一圈没找着洗发水,于是小卞对着一个营业员说:请问洗发水在哪儿?营业员很不耐烦地用上海话咕哝了几句,我们都没听懂,小卞再次很虚心地很不好意思地问:请问洗发水在哪儿?结果那营业员恶狠狠地用普通话说:就在后面,自己找!!小卞听了扭头就走,嘴里骂到:操,大不了老子今天不洗头了。
    怀旧还可以很诚恳地告诉大家,我每次去超市都是胆战心惊的,害怕得罪那些营业员,所以很少去超市,我宁可去菜场也不愿去超市,至少,在菜场还有很多对我笑脸相迎的农民。
    
    小卞总结:上海超市已经成了上海亚健康妇女的心情加油站!上海超市不和谐的购物环境与上海中年妇女自身性生活的不和谐状况有着最直接最根本的联系!小卞叫我在这篇博文里给予点名批评如下几家单位(排名不分先后):可的、好德、快客、良友金伴、伍缘、罗森、全家、华联、光明等等几乎所有的中小型超市。
    这些超市很小,东西却很贵,因为他们知道我们没时间到大超市去排队。我就不知道他们为什么要贵,很多小超市连空调都没有,而且收银台上还用电饭锅装了满满一大锅的不知道烧了多少天的茶叶蛋,散发出的阵阵鸡骚浸透了货架上的每一件商品。
    也许有人认为我说的有失偏颇,上海超市营业员中有不少还是少男少女。这个我承认,男的我不说,小伙子艰苦创业从底层做起值得表扬,可女的呢?通过仔细观察可以发现,这些女的长得都不好看,而且是一点都不好看,个别人长得还有点象男的,我见到过农工商超市有个少女营业员,怎么看怎么像赵本山年轻的时候。
    漂亮女人都哪去了?漂亮女人是不会做营业员的,漂亮女人是理所当然的消费者。这就是上海。
    
    
    南京是个让我感动的城市,别的超市不说,我就说南京的“苏果超市”吧,90%的收银员都是未婚少女,我是个到处留情的人,坦白说,我曾经真心喜欢过至少20位以上的苏果收银员,不管这种爱持续10分钟还是一个晚上亦或是一个月,在我心里,这样的爱是真诚的。
    上海的收银员只是个机器,南京的收银员可以做我的女友。我曾经因为“苏果超市”的一位少女收银员的一个眼神而对那家“苏果超市”留恋忘返,那段时间一天去两次,每次都买一瓶牛奶,为的就是能跟她说上几句话,或者看上一眼。她知道我爱她并且不讨厌我,但是我一直没有说出来,因为我那时有女朋友了。后来我就是为了她,把离开南京的日期硬是向后推迟了大半年。离开的时候,我没有去道别,因为我怕我们都忍不住掉泪。
    在上海做生意就是做生意,没人跟你谈感情;而在南京生意可以不做,而感情不能没有。上海的铜臭味更重一点,南京的人情味更浓一点。上海超市采用中年妇女作为营业员考虑了两个方面:一是工资低,二是过了哺乳期,没了产假,没了补贴。而南京超市却没有算计地那么清楚,他们更多地考虑了消费者的感受。今天我尤其代表那些碌碌无为的未婚青年在此表示感谢。
    所以我说,南京再精也精不过上海。
    
    再说“吃”,我还是拿南京跟上海作比较。(一是因为南京在某些方面可以代表中国绝大多数的中小城市;二是因为我对南京比较了解。)
    南京小吃很丰富,我吃过一些,听说上海小吃也很多,但吃的不多。我这人不爱吃小吃,所以没有资格多谈。上海小吃是为了打发那些下班之后碌碌饥肠的人们,他们根本就没有时间去细细品尝,只要填饱肚子就可以回家蒙头大睡了,所以上海小吃很难吃,几乎是难以下咽的,因为他的出发点是打发人,而不是创造和传承美食文化;而生活在南京这座文化古城的人们下班之后总有时间细嚼慢咽、品位生活、享受人生,自然他们对小吃的口味要求就提高了许多,烹调水平自然就上了一个台阶。上海的路边小吃店与南京随处可见的大排挡,是绝对不可相提并论的。
    在南京,我可以随便找个小店坐下来点两个小菜跟朋友喝点小酒,非常惬意。在上海,饭店比洗头房还多,可要找个口味不错的小店真的很难很难。大部分是滥竽充数、敷衍了事,没有一点职业精神,服务态度异常恶劣。如果你要一份回锅肉,他们不用辣椒不用大蒜反而用了细细的土豆丝,仔细一看那五花肉根本就没有用油炸过,你叫我怎么吃?早知道这样我不如要一份土豆肉丝算了。还有一次我吃振鼎鸡,向服务员要了三次餐巾纸,半小时了还没有给我送过来,我拍案而起大吼一声:把餐巾纸给老子送过来!结果5秒种不到,餐巾纸送到。
    如果你说南翔小笼还值得一尝的话,那么我说白玉兰小吃简直就是他吗的猪饲料,将热菜往冷饭上面一倒,美其名曰——盖浇饭!
    也许有人会问,这样的饭店是不是很便宜,是不是生意不好?今天我再一次很负责任地告诉大家,这样的饭店生意很好,而且一点都不便宜,每次都是爆满。为什么呀?别无选择啊!到处都是这样啊。饭店多,人比他吗的比饭店更多!只要有饭店的地方就有人,只要有人的地方就有饭店,没有一家饭店人庭寥落的。这就是上海!一大清早的马路边如果哪个摊主的饭团馒头豆浆油条稍微有一点点好吃的话,那么一不小心就排起了长长的队,就跟买彩票一样。这就是上海。
    可以这样说,在南京15元可以炒一荤一素两个很不错的小菜,老板还送汤,米饭随便吃多少只需加1元,“吃拔儿拔儿香”,如果你不炒菜改吃快餐,那也是个不错的选择,5块钱的快餐绝对物有所值

在上海,花20元也吃不到象样的晚饭,我真为上海的上班族感到难过。当然你可以花20元买20串羊肉串作为你最后的晚餐,但是你可以每天如此吗?就不怕吃出个羊癫疯?
    
    有人也许会反驳我说:“我不在饭店吃,我买菜回家自己做,我‘天天大米饭,日日小鱼汤’”。
    你说的不错,也许你是个勤劳的主妇,你有了你同居的伙伴,你们相儒以沫,你们同甘共苦。可是生活在上海的外地青年能有几个如你们这般闲情逸致呢?她们独来独往,他们意气风发,可有谁又知道他们每天下班之后会因为一顿美味的晚餐发愁呢?
    我曾经认识一个女孩子,她与另外5个女孩子合租一套2室一厅的小套房,她很不情愿地带我过去玩,我过去一看,屋子里连个坐的地方都没有,我只好坐床上,就跟他吗的嫖客一样。
    我问她我说你们平时一起买菜做饭吧,那么多女孩子,一定做饭很好吃吧,我以后常来吃了。她说,很少买菜,都是自己忙自己的肚子,烧点开水煮点泡面什么的就算完事了,或者吃点饼干、麻辣烫、煎饼、粉丝、面包什么的。因为每个人下班时间都不一样,很难聚到一起。即便是聚到一起了,那也是疲惫的时候了,饭做好了,食欲也没了。
    我听了以后感到相——当——的惊讶!在上海,吃一顿可口的家常菜是很多人的梦想。
    我没有想到如此漂亮的一群女孩子,平时都有体面的工作,一点都不象社会底层的人,怎么住在这样酷似难民营的陈旧住宅里,东凑一顿西凑一顿的,要是他们的父母知道了该是多么的寒心啊!我被深深地震撼了,我从来都没有同情过女人,可那个时候,我知道什么叫“怜香惜玉”了!难道,难道说生活在上海的MM们,都是这样的吗?我发誓我不会再去鄙视那些卖淫的人们。
    上海,吃人的上海。今天,我要让天下父母都知道他们的子女在上海都过着怎样的日子!
    也许他们缺少的不仅是一个共同买菜做饭的搭档,而是一个真正的朋友。生活在上海的孩子们,享受着空前的孤独。
    我还认识两个合租的男人,其中一个是我的网友,虽然他们合租一室,但作息时间的不同让他们一个星期也见不上几次面。二位老兄谈了几个女朋友都吹了,原因是不习惯在一个陌生人的房间隔壁以并不明朗的男女关系做爱,更不习惯坐在被一个陌生人的屁股刚刚温暖过的马桶上小便。没有一个宽松、自由、独立的空间去营造男女之间的感情,一想到是在别人的房子里做爱,彼此就没了高潮,这尴尬的生活葬送多少美丽的爱情!或许可以到宾馆去,但总不能每天都住宾馆。唉,恋爱中的帅男靓女啊,上海让你们憋屈了。
    缺乏了性爱的爱情该如何进行下去?上海,真的不是个恋爱的城市。
    现在我终于理解为什么有些女人要从自己每月6000元的工资中拿出4000元来,在高档酒店式公寓租借套房,——她们每天最大的任务就是试着在电梯里“偶遇”那些开着宝马的公子哥或单身款爷并无比渴望对方能跟自己搭讪几句。她们用自己几乎所有的积蓄来刻意地换取与上流社会的姻缘,对她们来说生命也许就是一场赌博。
    对于女人来说爱情是需要出卖的,对于男人来说,爱情是需要购买的,对于所有人来说,生活是需要挣扎的。这就是上海。
    都市浮华的背后隐藏着无数的孤魂。孤独啊孤独,孤独到了极点,必然要爆发。
    上海色情业的泛滥已经渐渐地超越了北京。北京有“天上人间”咱上海也有,北京有站街女咱上海有会所与足浴房。在我公司不远的地方有个会所经营不善,猖獗的妓女为钱丧命,上报之后停业整顿,三月之内改头换面继续干起了老本行,在很大程度上拢住了新老客户。
    如果走过一条不太繁华的街道,你会发现有很多理发店的标志灯箱在那里转悠转悠,咔!你就被转晕了,头一晕就进去了,20分钟出来,继续晕……这样的街道铺天盖地首尾相连,如果在空中将那些旋转的灯箱都连成线,一定酷似一张莫大的钢丝床,这张床笼罩了全上海。
    对于那些单身男人,这真的不失为一种合理而强劲的荷尔蒙解决方案,不用绞尽脑汁地去安排一次又一次毫无结果的约会,不用陪女孩吃完晚饭看完电影独自回家以后依然依靠自己平时用来操作鼠标的右手自我安慰。一次次地后悔,一次次地流泪,为什么总是戒不掉自慰?
    
    说起看电影,众所周知在上海,星期二看电影是半价的,因此这一天的人特别多,很多收入并不宽裕的男人就选择在这一天跟自己心仪的女人一起观看所谓狗屁导演折腾出来的所谓狗屎大片。我个人认为一个男人如果在电影票的价格上精打细算的话,可能他的爱情也会遭到女人的质疑。唉,没有办法,在上海没钱还真的不行!也许看完这场电影,这些男人又要为他们本月的伙食费忧心忡忡了。
    
    今年春节,我发现了一个怪现象,就是春节放假7天之内,上海的街道突然宽敞了起来,路上没几辆车在跑,交警也少了很多,值勤的辅警也几乎看不到了。我问朋友这是怎么回事。朋友说,上海买车开车的都是外地人,这些人都回家过年了,自然就空旷了。我恍然大捂,这是一座多么浮躁的城市,是人是狗都朝这里拥,也许就是图个上流社会的生活吧。每天忙忙碌碌,上班坐车吃饭睡觉,不断地跳槽,不断地面试,不断地搬家,不断地寻找新的交通路线,认识了一批又一批的新人,告别了一个又一个的朋友,多年以后发现自己还是孑然一生,工资没有变,积蓄全没了,激情燃烧的岁月也渐渐地暗淡了。不知不觉自己已经多了几根白发,所谓的上流,能够爬上去的毕竟是少数。
    
    亲爱的朋友们,能回家的赶快回家吧。上海真的不属于你们,如果哪一天你真的买了房子,那每月好几千元的房贷足以毁了你快乐的一生。不要用“好男儿志在四方”这句话来勉励自己,不可否认,你可能成功,但也许那并不是你真的想要的。也不要抱着“找个有钱人嫁掉”的梦想度日如年,那毕竟比彩票中奖的几率还低。
    我真心祝福那些孜孜不倦依然在此激情打拼的人们,一路走好。只是,以青春作为赌注,是不是有点不值。
    
    想起去年五一,我一个人回到老家,见到了我久别的父亲母亲。睡了一天的觉,很舒服,第二天起床,来到后院,看着竹林,听着鸟叫,小狗咬着我的裤管,风吹着我沧桑的脸,安静的我想起了烂漫的童年,回忆往事,我笑了起来。忽然,父亲在屋里问我:怀旧,你什么时候回上海,要带点香肠腊肉吗?
    “还没想好。”我无精打采地说。

- 作者: GeorgeKong 2006年12月16日, 星期六 10:55  回复(0) |  引用(0) 加入博采

XML/XSD/DTD
DTD:The purpose of a Document Type Definition is to define the legal building blocks of an XML document. It defines the document structure with a list of legal elements.

XML Schema:XML Schema is an XML based alternative to DTD.An XML schema describes the structure of an XML document.The XML Schema language is also referred to as XML Schema Definition (XSD).

CSS = HTML Style Sheets:HTML uses predefined tags and the meaning of the tags are well understood.

XSL = XML Style Sheets:XML does not use predefined tags (we can use any tag-names we like), and the meaning of these tags are not well understood.

DTD和Schema都是验证xml合法性的文档类型定义.DTD有其自身的语法,而Schema使用xml标记,而且支持更多的数据类型.因此,Schema慢慢将取代DTD.xml的优势在于它的通用性,尤其在网络上传输数据时.

XSD是XML Schema Definition的缩写,它本身也是XMl的一个变形子集,用于规定XMl文档的格式。举个例子说:“XMl是C语言,那么XSD就是你用C语言编写的类,而某个XMl数据文档就是你用刚刚编写的那个类的实例化,也就是按照类的定义申请了一个内存空间,并存储相应的数据。”

XSD是W3C推荐的XML SCHEMA标准,SCHEMA即描述XML的结构和元素关系的规则模式,他规定了一个xml文档可以使用那些元素、元素的类型以及一些限制规则。schema和DTD一样,都是描述xml的,只不过SCHEMA的内容更丰富,更具有扩展性,同时他本身也是一个xml文档,更方便解析。

- 作者: GeorgeKong 2006年10月10日, 星期二 08:50  回复(0) |  引用(0) 加入博采

已锁定
此日志的浏览权限已被作者锁定,请同作者联系,发送短消息,如果你的身份符合作者的要求,点击此处可以进行浏览

- 作者: GeorgeKong 2006年09月25日, 星期一 10:16  回复(0) |  引用(0) 加入博采

Crimson和Xerces恩仇录
      Crimson来自于Sun捐赠给Apache的ProjectX项目,Xerces来自IBM捐赠给Apache的XML4J项目,结果Xerces胜出,成了Apache XML小组全力开发的XML API,而Crimon已经早就不做了,如今Xerces名满天下,到处都是在用Xerces DOM和SAX解析器,只有Sun不服气,非要在JDK1.4里面使用过时的Crimson,让人感觉像是在赌气一样,真是让人可怜又可气!不过IBM发行JDK用的XML 解析器自然是Xerces。
 
      由于JDK的Class Loader的优先级关系,当你采用JAXP编写XML程序的时候,即使把Xerces包引入CLASSPATH,JDK还是会顽固的使用Crimson,这一点通过打开JVM的verbose参数可以观察到。不过JDK也允许你采用其它的解析器,因此我们可以通过在JRE\lib\目录下建一个jaxp.properties的文件,来替换解析器,jaxp.properties内容如下:
 
javax.xml.parsers.DocumentBuilderFactory=org.apache.xerces.jaxp.DocumentBuilderFactoryImpl
javax.xml.parsers.SAXParserFactory=org.apache.xerces.jaxp.SAXParserFactoryImpl
 
这样就可以使用Xerces,当然你必须还是要把Xerces包放到CLASSPATH下。

- 作者: GeorgeKong 2006年09月15日, 星期五 15:29  回复(0) |  引用(0) 加入博采

Web 2.0

译者序:Web 2.0这一概念,由O'Reilly媒体公司总裁兼CEO提姆·奥莱理提出。他是美国IT业界公认的传奇式人物,是“开放源码”概念的缔造者,一直倡导开放标准,并活跃在开放源码运动的最前沿。

  这篇由提姆·奥莱理亲自执笔、创作于上个月由他主办的Web 2.0会议前夕的文章,一经发出就引发了热烈的讨论,被视为Web 2.0迄今为止的经典之作。

  Web2.0的一个关键原则是用户越多,服务越好

  作者|提姆·奥莱理(Tim O'Reilly) 翻译作者|玄伟剑

  2001年秋天互联网公司(dot-com)泡沫的破灭标志着互联网的一个转折点。许多人断定互联网被过分炒作,事实上网络泡沫和相继而来的股市大衰退看起来像是所有技术革命的共同特征。股市大衰退通常标志着蒸蒸日上的技术已经开始占领中央舞台。假冒者被驱逐,而真正成功的故事展示了它们的力量,同时人们开始理解了是什么将一个故事同另外一个区分开来。

  “Web 2.0”的概念开始于一个会议中,展开于O'Reilly公司和MediaLive国际公司之间的头脑风暴部分。所谓互联网先驱和O'Reilly公司副总裁的戴尔·多尔蒂(Dale Dougherty)注意到,同所谓的“崩溃”迥然不同,互联网比其他任何时候都更重要,令人激动的新应用程序和网站正在以令人惊讶的规律性涌现出来。更重要的是,那些幸免于当初网络泡沫的公司,看起来有一些共同之处。那么会不会是互联网公司那场泡沫的破灭标志了互联网的一种转折,以至于呼吁“Web 2.0”的行动有了意义?我们都认同这种观点,Web 2.0会议由此诞生。

  在那个会议之后的一年半的时间里,“Web 2.0”一词已经深入人心,从Google上可以搜索到950万以上的链接。但是,至今关于Web 2.0的含义仍存在极大的分歧,一些人将Web 2.0贬低为毫无疑义的一个行销炒作口号,而其他一些人则将之理解为一种新的传统理念。

  本文就是来尝试澄清Web 2.0本来意义。

  在我们当初的头脑风暴中,我们已经用一些例子,公式化地表达了我们对Web 2.0的理解:

Web 1.0Web 2.0
DoubleClickGoogle AdSense
OfotoFlickr
AkamaiBitTorrent
mp3.comNapster
大英百科全书在线(Britannica Online)维基百科全书(Wikipedia)
个人网站博客(blogging)
evite upcoming.org和EVDB
域名投机搜索引擎优化
页面浏览数每次点击成本
屏幕抓取(screen scraping)网络服务(web services)
发布参与
内容管理系统维基
目录(分类)标签(“分众分类”,folksonomy)
粘性聚合

  这个列表还会不断继续下去。但是到底是什么,使得我们认定一个应用程序或一种方式为作所谓“Web 1.0”,而把另外一个叫做“Web 2.0”呢?(这个问题尤为紧迫,因为Web 2.0的观念已经传播的如此广泛,以至于很多公司正在将这个词加到他们的行销炒作中,但却没有真正理解其含义。同时这个问题也尤为困难,因为许多嗜好口号的创业公司显然不是Web 2.0,而一些我们认为是Web 2.0的应用程序,例如Napster和BitTorrent,甚至不是真正适当的网络程序!)我们首先来探讨一些原则,这些原则是通过Web 1.0的一些成功案例,以及一些最为有趣的新型应用程序来体现的。

  

  1. 互联网作为平台

  正如许多重要的理念一样,Web 2.0没有一个明确的界限,而是一个重力核心。不妨将Web 2.0视作一组原则和实践,由此来把距离核心或远或近的网站组成为一个类似太阳系的网络系统,这些网站或多或少地体现着Web 2.0的原则。

  图1为Web 2.0的“模拟图”,该图是在名为“O'Reilly的朋友”(Friend Of O'Reilly, FOO)的会议的一个研讨会上产生的。这个图基本上仍处于演化阶段,但已经描绘出了 从Web 2.0核心理念中衍生出的许多概念。

  例如,在2004年10月的第一次Web 2.0的会议上,约翰·巴特利(John Battelle)和我在我们各自的开场白中列举了一组初步的原则。

  这些原则中的第一条就是“互联网作为平台”。这也曾是Web 1.0的宠儿网景公司(Netscape)的战斗口号,而网景在同微软的大战中陨落了。此外,我们早先的Web 1.0的楷模中的两个,DoubleClick和Akamai公司,皆是将网络当作平台的先驱。人们往往不认为这是一种网络服务,但事实上,广告服务是第一个被广泛应用的网络服务,同时也是第一个被广泛应用的混合处理(mashup),如果用另一个近来流行的词来说的话。每个旗帜广告(banner ad)都是用来在两个网站之前无缝合作,向位于另外一台计算机上的读者传递一个整合好的页面。

  Akamai也将网络看作平台,并且在一个更深入的层次上,来搭建一个透明的缓存和内容分发网络,以便降低宽带的拥塞程度。

  虽然如此,这些先驱提供了有益的对比,因为后来者遇到同样问题的时候,可以将先驱们的解决方案进一步延伸,从而对新平台本质的理解也更为深刻了。DoubleClick和Akamai都是Web 2.0的先驱,同时我们也可以看到,可以通过引入更多Web 2.0的设计模式,来实现更多的应用。

  让我们对这三个案例中的每一个都作一番深究,来探讨其间的一些本质性的差别。

  Netscape 对 Google

  如果Netscape可以称为Web 1.0的旗手,那么Google几乎可以肯定是Web 2.0的旗手,只要看看他们的首次公开上市(IPO)是如何地揭示了各自的时代就清楚了。所以我们就从这两个公司和其定位的差别入手。

  Netscape以传统的软件摹本来勾勒其所谓“互联网作为平台”:他们的旗舰产品是互联网浏览器,一个桌面应用程序。同时,他们的战略是利用他们在浏览器市场的统治地位,来为其昂贵的服务器产品建立起市场。从理论上讲,在浏览器中控制显示内容和程序的标准,赋予了Netscape一种市场支配力,如同微软公司在个人计算机市场上所享受的一样。很像当初“自行的马车”(horseless carriage)将汽车描绘为一种熟知事物的延伸,Netscape曾推销一种网络桌面(webtop)来替代传统的桌面(desktop),并且计划借助信息更新,以及由购买了Netscape服务器的信息提供者来推送的各种小程序,来开发推广这种网络桌面。

  最终,浏览器和网络服务器都变成了“日用品”,同时价值链条也向上移动到了在互联网平台上传递的服务。

  作为对比,Google则以天生的网络应用程序的角色问世,它从不出售或者打包其程序,而是以服务的方式来传递。客户们直接或间接地为其所使用的服务向Google付费。原有软件工业缺陷荡然无存。没有了定期的软件发布,只需要持续的改善。没有了许可证或销售,只需要使用。没有了为了让用户在其设备上运行软件而不得不进行的平台迁移,只需要搭建宏大的、由众多个人计算机组成的、可伸缩的网络,其上运行开源操作系统,及其及自行研制的应用程序和工具,而公司之外的任何人则永远无法接触到这些东西。

  在其底层,Google需要一种Netscape从未需要过的能力:数据库管理。Google远远不只是一个软件工具的集合,它是一个专业化的数据库。没有这些数据,那些工具将毫无用武之地;没有这些软件,数据也将无可控制。软件许可证制度和对应用程序接口(API)的控制——上一个时代的法宝——已经毫不相关了,因为Google的软件只需要执行而从不需要分发,也因为如果不具备收集和管理数据的能力,软件本身就没有什么用处了。事实上,软件的价值是同它所协助管理的数据的规模和活性成正比的。

  Google的服务不是一个简单的服务器,虽然其服务是通过大规模的互联网服务器集合来传递的;其服务也不是一个浏览器,虽然这种服务是被用户在浏览器中体验到的。Google的旗舰产品——搜索服务,甚至不托管它让用户来搜寻的内容。很像一个电话通话过程,不仅发生在通话的两端,而且发生在中间的网络上。作为用户和其在线体验的一个中介,Google作用于浏览器、搜索引擎和最终的内容服务器之间的空间中。

  虽然Netscape和Google都可以被描述为软件公司,但显然Netscape可以归到Lotus,Microsoft,Oracle,SAP,以及其他发源于上个世纪八十年代软件革命的那些公司所组成的软件世界。而Google的同伴们,则是像eBay,Amazon,Napster,及至DoubleClick和Akamai这样的互联网公司。

  DoubleClick对Overture和AdSense

  同Google类似,DoubleClick是一个名副其实的互联网时代的孩子。它把软件作为一种服务,在数据管理方面具有核心竞争力,并且正如上文所述,它是一个早在连网络服务的名字还不曾有的时候,就已然开始其服务的先驱。然而,DoubleClick最终还是被其商业模式局限住了。它所贯彻的是九十年代的互联网观念。这种观念围绕着出版,而不是参与;围绕着广告客户,而不是消费者,来进行操纵;围绕着规模,认为互联网会被如MediaMetrix等网络广告评测公司尺度下的所谓顶级网站所统治。

  结果是,DoubleClick得意地在其网站上引用道:“超过2000种的成功应用”。而相对比的是,Yahoo!公司的搜索市场(从前的Overture)和Google的AdSense产品,已经在为几十万的广告客户服务。

  Overture和Google的成功源自于对克里斯·安德森(Chris Anderson)提到的所谓“长尾”的领悟,即众多小网站集体的力量提供了互联网的大多数内容。DoubleClick的产品要求一种签订正式的销售合同,并将其市场局限于很少的几千个大型网站。Overture和Google则领会到如何将广告放置到几乎所有网页上。更进一步地,它们回避了发行商和广告代理们所喜爱的广告形式,例如旗帜广告和弹出式广告,而采用了干扰最小的、上下文敏感的、对用户友好的文字广告形式。

  Web 2.0的经验是:有效利用消费者的自助服务和算法上的数据管理,以便能够将触角延伸至整个互联网,延伸至各个边缘而不仅仅是中心,延伸至长尾而不仅仅是头部。

  毫不奇怪,其他Web 2.0的成功故事也显示着同样的轨迹。eBay扮演着一个自动的中间媒介的角色,使个体之间发生的几个美元的偶然性的交易成为可能。Napster(虽然已经出于法律原因而关闭)将其网络建立在一个集中的歌曲数据库之上,但是它让每一个下载者都成为一台服务器,从而使其网络逐渐扩大。

  Akamai 对 BitTorrent

  同DoubleClick类似,Akamai的业务重点面向网络的头部,而不是尾部;面向中心,而不是边缘。虽然它服务于那些处于网络边缘的个体的利益,为他们访问位于互联网中心的高需求的网站铺平了道路,但它的收入仍然来自从那些位于中心的网站。

  BitTorrent,像P2P风潮中的其他倡导者一样,采用了一种激进的方式来达到互联网去中心化(internet decentralization)的目的。每个客户端同时也是一个服务器;文件被分割成许多片段,从而可以由网络上的多个地方提供,透明地利用了网络的下载者来为其他下载者提供带宽和数据。事实上,文件越流行下载得越快,因为有更多的用户在为这个文件提供带宽和各个片段。

  BitTorrent由此显示出Web 2.0的一个关键原则:用户越多,服务越好。一边是Akamai必须增加服务器来改善服务,另一边是BitTorrent用户将各自的资源贡献给大家。可以说,有一种隐性的“参与体系”内置在合作准则中。在这种参与体系中,服务主要扮演着一个智能代理的作用,将网络上的各个边缘连接起来,同时充分利用了用户自身的力量。

  2. 利用集体智慧

  在诞生于Web 1.0时代并且存活了下来,而且要继续领导Web 2.0时代的那些巨人的成功故事的背后,有一个核心原则,就是他们借助了网络的力量来利用集体智慧:

  --超级链接是互联网的基础。当用户添加新的内容和新的网站的时候,将被限定在一种特定的网络结构中,这种网络结构是由其他用户发现内容并建立链接的。如同大脑中的神经突触,随着彼此的联系通过复制和强化变得越来越强,而作为所有网络用户的所有活动的直接结果,互联的网络将有机地成长。

  --Yahoo!是第首例伟大的成功故事,诞生于一个分类目录,或者说是链接目录,一个对数万甚至数百万网络用户的最精彩作品的汇总。虽然后来Yahoo!进入了创建五花八门的内容的业务,但其作为一个门户来收集网络用户们集体作品的角色,依然是其价值核心。

  --Google在搜索方面的突破在于PageRank技术,该技术令其迅速成为搜索市场上毫无争议的领导者。PageRank是一种利用了网络的链接结构,而不是仅仅是使用文档的属性,来实现更好的搜索效果的方法。

  --eBay的产品是其全部用户的集体活动,就向网络自身一样,eBay随着用户的活动而有机地成长,而且该公司的角色是作为一个特定环境的促成者,而用户的行动就发生在这种环境之中。更重要的是,eBay的竞争优势几乎都来自于关键性的大量的买家和卖家双方,而这正是这一点使得后面许多竞争者的产品的吸引力显著减低。

  --Amazon销售同Barnesandnoble.com等竞争者相同的产品,同时这些公司从卖方获得的是同样的产品描述、封面图片和目录。所不同的是,Amazon已然缔造出了一门关于激发用户参与的科学。Amazon拥有比其竞争者高出一个数量级以上的用户评价,以及更多的邀请来让用户以五花八门的方式,在近乎所有的页面上进行参与,而更为重要的是,他们利用用户的活动来产生更好的搜索结果。Barnesandnoble.com的搜索结果很可能指向该公司自己的产品,或者是赞助商的结果,而Amazon则始终以所谓“最流行的”打头,这是一种实时计算,不仅基于销售,而且基于其他一些被Amazon内部人士称为围绕着产品“流动”(flow)的因素。由于拥有高出对手一个数量级的用户参与,Amazon销售额超出竞争对手也就不足为奇了。

  现在,具备了这种洞察力,并且可能会将之延伸开来的那些创新型的公司,正在互联网上留下他们的印迹。

  维基百科全书(Wikipedia)是一种在线百科全书,其实现基于一种看似不可能的观念。该观念认为一个条目可以被任何互联网用户所添加,同时可以被其他任何人编辑。无疑,这是对信任的一种极端的实验,将埃里克·雷蒙德(Eric Raymond)的格言(源自开放源码软件的背景之下):“有足够的眼球,所有的程序缺陷都是肤浅的”(with enough eyeballs, all bugs are shallow)运用到了内容的创建之中。维基百科全书已然高居世界网站百强之列,并且许多人认为它不久就将位列十强。这在内容创建方面是一种深远的变革。

  像del.icio.us(美味书签)和Flickr这样的网站,其公司已经在近期获得了广泛的关注,并且已经在一种被人们成为“分众分类”(folksonomy,有别于传统分类法)的概念上成为先行者。“分众分类”是一种使用用户自由选择的关键词对网站进行协作分类的方式,而这些关键词一般称为标签(tags)。标签化运用了像大脑本身所使用的那种多重的、重叠的关联,而不是死板的分类。举一个经典的例子,在Flickr网站上,一幅小狗照片可能被加上“小狗”和“可爱”这样的标签,从而允许系统依照用户行为所产生的自然的方式来进行检索。

  协作式垃圾信息过滤产品,例如Cloudmark,就聚集了电子邮件用户们对于“一封邮件是或者不是垃圾邮件”的众多相互独立的决策,从而胜过了依赖于分析邮件本身的那些系统。

  伟大的互联网成功者并不主动地到处推销其产品,这几乎成为公理。他们采用“病毒式营销”(viral marketing)的方式,也就是说,一些推介会直接从一个用户传播到另外一个用户。如何一个网站或产品依赖广告来进行宣传,你几乎可以断定它不是Web 2.0。

  即便许多互联网基础设施本身,包括在大多数网络服务器中用到的Linux,Apache,MySQL,以及Perl,PHP或Python代码,也都依靠开放源码的对等生产(peer-production)的方式。其中包含了一种集体的、网络赋予的智慧。在SourceForge.net网站上列有至少10万种开放源码软件项目。任何人都可以添加一个项目,任何人都可以下载并使用项目代码。

  同时,由于作为用户使用的结果,新的项目从边缘迁移到中心。一个对软件的有机的接受过程几乎完全依靠病毒式营销。同时,作为用户应用的结果,新的项目从边缘迁移到中心,这是一种几乎完全依靠病毒式营销的,有机的软件采用过程,。

  经验是:源于用户贡献的网络效应,是在Web 2.0时代中统治市场的关键。

  平台总是打败应用程序

  在过去每次同对手的竞争中,微软都成功地打用了平台这张牌,打败了即便是最占主导地位的应用程序。Windows平台让微软以Excel取代了Lotus 1-2-3,以Word取代了WordPerfect,,以Internet Explorer取代了Netscape浏览器。

  不过这次,冲突不是在平台和应用程序之间,而是在两种平台之间。每个平台皆有一种截然不同的商业模式:一方面,一个独立软件商具有广泛的用户基础并且将应用程序接口和操作系统紧密集成,从而对程序设计模式予以控制;另一方面,是一个没有所有者的系统,由一组协议、开放标准和对合作的共识来连结到一起。

  Windows系统代表了由软件程序接口来进行专有控制的高峰。Netscape曾尝试用微软当初对付其对手所使用的手段,来同微软进行争夺,但是失败了。然而拥有互联网开放标准的Apache却已经繁荣了起来。此番上演的战局,已经不再是实力悬殊的平台对决孤立的软件了,而是变成了平台对决平台。问题在于,哪个平台,或者更深远地来说哪个体系,以及哪个商业模式,最能适应未来的机遇。

  Windows对于早期的PC时代的问题是一种卓越的解决方案。它统一了程序开发者的竞技场,解决了很多困扰这个领域的问题。但这种由单一供方控制的一刀切的方法,已经不再是适宜的解决方案,而成为了一种问题。面向交流的系统需要协同性,互联网作为一个平台当然也是如此。除非供方可以控制每一例交互的两个终端,这种通过软件的程序接口来锁定用户的可能性微乎其微。

  任何企图通过控制平台来推销应用程序的Web 2.0提供商,从定义上讲,已经丧失了这个平台的优越性。

  这并不是说锁定和竞争优势的机会不复存在了,而是说我们相信这种机会不是通过控制软件程序接口和协议来取得的。新的游戏规则正在浮现。那些能够理解这些新的游戏规则,而不是企图回到PC软件时代旧有规则的公司,才有可能在Web 2.0时代获得成功。

  博客和大众智慧

  Web 2.0时代一项最受追捧的特性就是博客的兴起。个人主页从互联网早期就已经存在了,而个人日记和每日发表观点的专栏就更渊源久远了,那么到底有什么让人大惊小怪的呢?

  归根底地,博客只是一种日记形式个人网页。但正如里奇·斯格仁塔(Rich Skrenta)指出的,博客的按时间顺序来排列的结构“看起来像是一个微不足道的变化,但却推动着一个迥然不同的分发、广告和价值链。”

  其中一大变化就是一项称为RSS的技术。RSS是自早期计算机高手们认识到CGI(公共网关接口)可用来创建以数据库为基础的网站以来,在互联网根本结构方面最重要的进步。RSS使人们不仅仅链接到一个网页,而且可以订阅这个网页,从而每当该页面产生了变化时都会得到通知。斯格仁塔将之称为“增量的互联网”(incremental web)。其他人则称之为“鲜活的互联网”(live web)。

  当然,现在所谓“动态网站”(即具有动态产生的内容的、由数据库驱动的网站)取代了十年前的静态网站。而动态网站的活力不仅在于网页,而且在链接方面。一个指向网络博客的链接实际上是指向一个不断更新的网页,包括指向其中任何一篇文章的“固定链接”(permalinks),以及每一次更新的通知。因此,一个RSS是比书签或者指向一个单独网页的链接要强大得多。

  RSS同时也意味着网页浏览器不再只是限于浏览网页的工具。尽管诸如Bloglines之类的RSS聚合器(RSS aggregators)是基于网络的,但其他的则是桌面程序,此外还有一些则可以用在便携设备上来接受定期更新的内容。

  RSS现在不仅用于推送新的博客文章的通知,还可以用于其他各种各样的数据更新,包括股票报价、天气情况、以及图片。这类应用实际上是对RSS本源的一种回归:RSS诞生于1997年,是如下两种技术的汇合:一种是戴夫·温纳(Dave Winer)的“真正简单的聚合”(Really Simple Syndication)技术,用于通知博客的更新情况;另一种是Netscape公司提供的“丰富站点摘要”(Rich Site Summary)技术,该技术允许用户用定期更新的数据流来定制Netscape主页。后来Netscape公司失去了兴趣,这种技术便由温纳的一个博客先驱公司Userland承接下来。不过,在现在的应用程序实现中,我可以看出两者共同的作用。

  但是,RSS只是令博客区别于同普通网页的一部分原因。汤姆·科特斯(Tom Coates)这样评论固定链接的重要性:

  “现在它可能看上去像是一项普普通通的功能,但它却有效地将博客从一个易于发布(ease-of-publishing)的现象,进一步转变为互相交叉的社区的一种对话式的参与。这是首次使得对其他人的网站上的很特定的帖子表态和谈论变得如此地容易。讨论出现了,聊天也出现。同时,其结果是出现了友谊或者友谊更加坚定了。固定链接是第一次也是最为成功的一次在博客之间搭建桥梁的尝试。”

  在许多方面,RSS同固定链接的结合,为HTPP(互联网协议)增添了NNTP(新闻组的网络新闻协议)的许多特性。所谓“博客圈”(blogosphere),可以将其视作一种同互联网早期的、以对话方式来灌水的新闻组和公告牌相比来说,新型的对等(peer-to-peer)意义上的等价现象。人们不仅可以相互订阅网站并方便地链接到一个页面上的特定评论,而且通过一种称为引用通告(trackbacks)的机制,可以得知其他任何人链接到了他们的页面,并且可以用相互链接或者添加评论的方式来做出回应。

  有趣的是,这种双向链接(two-way links)曾是象Xanadu之类的早期超文本系统的目标。超文本纯粹论者已然将引用通告颂扬为向双向链接迈进了一步。但需要注意的是,引用通告不是一个真正的双向链接,确切地讲是一种(潜在地)实现了双向链接效果的对称式单向链接。其间的区别看起来可能很细微,但实际上却是巨大的。诸如Friendster, Orkut和LinkedIn那样的社交网络系统(social networking systems),需要接受方做出确认以便建立某种连接,从而缺少像互联网架构本身那样的可伸缩性。正如照片共享服务Flickr网站的创始人之一卡特里纳·费克(Caterina Fake)所指出的,注意力仅在碰巧时才礼尚往来。(Flickr因此允许用户设置观察列表,即任何用户都可以通过RSS来订阅其他所有用户的照片流。注意的对象将会被通知,但并不一定要认可这种连接。)

  如果Web 2.0的一个本质是利用集体智慧,来将互联网调试为一种所谓的全球的大脑,那么博客圈就是前脑中喋喋不休的呓语,那种我们整个头脑中都能听到的声音。这可能并不反映出大脑的往往是无意识的深层结构,但却是一种有意识的思考的等价物。作为一种有意识的思考和注意力的反映,博客圈已经开始具有强有力的影响。

  首先,因为搜索引擎使用链接结构来辅助预测有用的页面,作为最多产和最及时的链接者,博客们在修整搜索引擎结果方面充当着一种不成比例的角色。其次,因为博客社区是如此多地自相引用,关注其他博客的博客们开阔了他们的视野和能力。此外,评论家们所批判的“回音室”(echo chamber)也是一种放大器。

  如果只是一种放大器,那么撰写博客将会变得无趣。但是像维基百科全书一样,博客将集体智慧用作一种过滤器。被詹姆士·苏瑞奥维奇(James Suriowecki)称为“大众智慧”(the wisdom of crowds)的规律起了作用,并且就像PageRank技术所产生的结果胜过分析任何单一文档一样,博客圈的集体关注会筛选出有价值的东西。

  虽然主流媒体可能将个别的博客视为竞争者,但真正使其紧张的将是同作为一个整体的博客圈的竞争。这不仅是网站之间的竞争,而且是一种商业模式之间的竞争。Web 2.0的世界也正是丹·吉尔默(Dan Gillmor)的所谓“个人媒体”(We,the media)的世界。在这个世界中,是所谓“原本的听众”,而不是密实里的少数几个人,来决定着什么是重要的。

  3. 数据是下一个Intel Inside

  现在每一个重要的互联网应用程序都由一个专门的数据库驱动:Google的网络爬虫, Yahoo!的目录(和网络爬虫),Amazon的产品数据库,eBay的产品数据库和销售商,MapQuest的地图数据库,Napster的分布式歌曲库。正如哈尔·瓦里安(Hal Varian)在去年的私人对话中谈到的,“SQL是新的HTML”。数据库管理是Web 2.0公司的核心竞争力,其重要性使得我们有时候称这些程序为“讯件”(infoware)而不仅仅是软件。

  该事实也引出了一个关键问题:谁拥有数据?

  在互联网时代,我们可能已经见到了这样一些案例,其中对数据库的掌控导致了对市场的支配和巨大的经济回报。当初由美国政府的法令授权给Network Solutions公司(后被Verisign公司收购)的对域名注册的垄断,曾经是互联网上的第一个摇钱树。虽然我们在争论通过控制软件的API来形成商业优势在互联网时代会变得困难得多,但是对关键数据资源的控制则不同,特别是当要创建这些数据资源非常昂贵,或者经由网络效应容易增加回报的时候。

  注意一下由MapQuest, maps.yahoo.com,maps.msn.com,或者maps.google.com等网站提供的每张地图下面的版权声明,你会发现这样一行字“地图版权NavTeq,TeleAtlas”,或者如果使用的是新的卫星图像服务,则会看到“图像版权Digital Globe”的字样。这些公司对其数据库进行了大量的投资。(仅NavTeq一家,就公布投资7.5亿美元用于创建其街道地址和路线数据库。Digital Globe则投资5亿美元来启动其自有卫星,来对政府提供的图像进行改进。)NavTeq竟然已做了很多模仿Intel的耳熟能详的Intel Inside标识的事:例如带有导航系统的汽车就带有“NavTeq Onboard”的印记。数据是许多此类程序事实上的Intel Inside,是一些系统的唯一的信息源组件,这些系统的软件体系多数是开放源码的,也有商业化的。

  当前竞争火热的网络地图(web mapping)领域显示着,对拥有软件核心数据的重要性的疏忽大意,将最终削弱其竞争地位。MapQuest在1995年率先进入地图领域,随后是Yahoo!,再后来是Microsoft,而最近Google也决定挺进这一市场,他们可以轻松地通过对同一数据的授权来提供一个具有竞争力的程序。

  然而,作为对比的是Amazon.com的竞争地位。像Barnesandnoble.com这样的竞争者一样,其原始数据库来自于ISBN注册商.R. Bowker。但是同MapQuest不同,Amazon大力增强其数据,增加出版商提供的数据,例如封面图片,目录,索引,和样张材料。更重要的是,他们利用了其用户来评注数据,以至于十年之后,是Amazon而不是Bowker,成为图书文献信息的主要来源,一个学者、图书管理员和消费者的参考书目来源。Amazon还引入了其专有的标识符,即ASIN,该标识符在ISBN存在时与之对应,而当产品不带有ISBN时,就创建出一个等价的命名空间。Amazon从而有效地“吸收和拓展了”其数据提供商。

  设想如果MapQuest也已做了同样的事情,利用他们的用户来评注地图和路线,添加新的价值层面。那么对仅仅通过授权使用基础数据来进入这一市场的其他竞争者,将造成远远大得多的困难。

  近期Google地图的引入,为应用程序销售商和其数据提供商之间的竞争,提供了一个活生生的实验室。Google的轻量型编程模型已经引发了不计其数的增值服务的出现,这些服务以数据混合的方式,将Google的地图同其他可以通过互联网访问的数据源相结合。保罗·拉特马赫(Paul Rademacher)的housingmaps.com是这种混合的一个上佳范例,其网站将Google的地图同Craigslist的公寓出租,以及住宅购买数据相结合,来创建一种交互式的房屋搜索工具。

  目前,这些混合大多是由程序高手们实现的创新性的实验产品。但是企业行动将紧随其后。并且,人们已经可以从至少一类开发者中发现这一点。Google已经将数据源提供者的角色从Navteq那里夺走,并且将自己定位为一个令人喜爱的中介者。在以后几年里,我们将会看到数据提供商和程序销售商之间的斗争,因为两大阵营都认识到了,特定的数据类别在作为搭建Web 2.0程序的积木时是多么的重要。

  这场竞赛已经涉及到拥有特定类别的核心数据:位置、身份、公共事件日历、产品标识和命名空间等。在许多情况下,在那些创建数据需要巨额成本的地方,也可能存在一种如同Intel Inside方式一样凭借单一数据源来所有作为的机遇。其他情况下,胜者将是那些通过用户聚合来达到临界规模,并且将聚合的数据融入系统服务中的公司。

  比如,在身份标识领域,PayPal,Amazon的一键式,以及拥有数百万用户的交流系统,都有可能成为创建整个网络范围的身份标识数据库的正当竞争者。(关于此,Google最近使用手机号码作为Gmail账号标识的尝试,可能就是朝借鉴和拓展电话系统所迈出的一步。)同时,像Sxip这样的创业公司,正在探索联合身份标识的可能性,以寻求一种“分布一键式”,从而提供一个无缝的Web 2.0标识子系统。在日历领域,EVDB则是通过维基式参与体系来搭建世界上最大的共享日历的一种尝试。虽然评判者尚在观望着任何一个特定创业公司或方式的成功是否,但很显然,这些领域的标准和解决方案,有效地将某些数据转变为“互联网操作系统”(internet operating system)的可靠的子系统,并将促成下一代的应用程序。

  关于数据,必须注意一个进一步的方面,那就是用户关心其隐私和对自己的数据的权限。在许多早期的网络程序中,版权只被松散地执行。例如,Amazon宣称对任何提交到其网站的评论的所有权,但却缺少强制性,人们可以将同样的评论转贴到其他任何地方。然而,随着很多公司开始认识到,对数据的掌控有可能成为他们首要的竞争优势来源,我们将会看到在此类控制方面强度更大的尝试。

  正如专有软件的增长而导致自由软件运动一样,在下一个10年中我们会看到专有数据库的增长将导致自由数据运动。在像维基百科全书这样的开放数据项目、创作共用(Creative Commons)、以及像Greasemonkey(让用户决定如何在其计算机上显示数据)这样的软件项目中,我们可以看到这种对抗势头的前兆。

  参与的体系

  一些系统被设计为鼓励参与。在丹·布莱克林(Dan Bricklin)的论文“共用的丰饶”(The Cornucopia of the Commons)中,他指出有三种创建大型数据库的方式。第一种,已经由Yahoo!来体现了,就是付费给人们来实现。第二种,由开放源码社区的经验启发而来,就是让志愿者来完成同样的任务。开放目录项目(Open Directory Project),一个Yahoo的开放源码竞争者,就是该方式的产物。但是Napster体现了第三种方式。因为Napster将其默认设置为自动为任何已经下载的音乐服务,任何用户都自动地帮助建立共享数据库的价值。同样的方式已经被其他所有P2P文件共享服务所采用。Web 2.0时代的一个关键经验在于:用户增加价值。但是只有很小一部分用户会有意来为你的程序增加价值,而不怕麻烦。因而,Web 2.0公司均进行了这样的默认设置,即作为程序通常使用方式的副产品,来聚合用户数据并创造价值。正如上面所指出的,他们在搭建那种用户越多则效果越好的系统。

  米切尔·卡普尔(Mitch Kapor)曾经指出“体系是策略”。参与是Napster的本质,其根本体系的一部分。

  同更经常被引用的所谓“吸引志愿精神”的原因相比,这种体系结构上的洞察力可能更能抓住对开放源码软件成功的本质。互联网、万维网(World Wide Web)、以及像Linux、Apache和Perl这样的开放源码软件项目的体系结构,均是这样一种设计,使得作为一种自动产生的副产品,谋求其自身利益的用户们创建着集体的价值。这些项目中的任何一个都有一个很小的核心、一种设计良好的扩展机制、和一种让任何人来添加任何合乎规定的组件的方式,不断增长着被Perl语言的创始人拉里·沃尔(Larry Wall)称为“洋葱头”(the onion)的外部层面。换句话说,这些技术通过他们本来的设计方式,体现着网络的效应。

  4. 软件发布周期的终结

  如上文在对Google和Netscape的比较中谈到的,互联网时代软件的代表性特征就是它应该被作为服务来交付。这种事实导致这类公司的商业模式上很多根本性的变化。

  1. 运营必须成为一种核心竞争力。Google或者Yahoo!在产品开发方面的专门技术,必须同日常运营方面的专门技术相匹配。从软件作为制造品到软件作为服务的变化是如此地根本,以至于软件将不再能完成任务,除非每日加以维护。Google必须持续抓取互联网并更新其索引,持续滤掉链接垃圾和其他影响其结果的东西,持续并且动态地响应数千万异步的用户查询,并同步地将这些查询同上下文相关的广告相匹配。

  所以,Google的系统管理、网络、和负载均衡技术,可能比其搜索算法更被严加看管,也就不足为奇了。Google在自动化这些步骤上的成功是其同竞争者相比更有成本优势的一个关键方面。

  同样也不足为奇的是,像Perl、Python、PHP、和当前的Ruby这样的脚本语言在Web 2.0公司中扮演着重要角色。Sun公司的第一个网管哈桑·施罗德(Hassan Schroeder)曾对Perl有一个著名的形容:“互联网的管道胶带”(the duct tape of the internet)。事实上,动态语言(常常被称为脚本语言,并被软件制品时代的软件工程师所贬低),是系统和网络管理员,以及创建可经常更新的动态系统的程序开发者们所喜爱的工具。

  2. 用户必须被作为共同开发者来对待,这是从对开放源码开发实践的一种反思中得出的(即便所涉及的软件不太可能以开放源码授权方式来发行)。开放源码的格言“早发布并常发布”(release early and release often)事实上已经演变成一种更为极端的定位“永远的测试版”(the perpetual beta)。其中产品在开放状态下开发,新的功能以每月、每周、甚至每天的速度被加入进来。Gmail、Google Maps、Flickr、del.icio.us,和其他类似的服务,可能会在某个阶段打着测试版的标识多年。

  故此,实时地监测用户行为,来考察哪些新特性被使用了,以及如何被使用的,将成为另外一种必须的核心竞争力。一位工作于一个主要在线服务网络商的开发者评论道:“我们每天在网站的某些部分提供两到三个新的特性,而且如果用户不采用它们,我们就将其撤掉。如果用户喜欢它们,我们就将其推广到整个网站。”

  Flickr的总开发师卡尔·亨德森(Cal Henderson),近来透露了他们是如何在短至每半个小时就部署一个新版本的。显而易见,这是同传统方式有天壤之别的开发模式。虽然不是所有的网络程序都以像Flickr这样的极端方式来开发,但几乎所有网络程序都有一个同任何PC或者客户-服务器时代截然不同的开发周期。正因如此,ZDnet杂志才论断Microsoft不会打败Google:“Microsoft的商业模式依赖于每个人在每两到三年都升级他们的计算环境。Google的模式则依靠任何人每天在其计算环境中自行探索新东西。”

  虽然Microsoft已经体现了从竞争中学习并最终做得最好的强大能力,但是毫无疑问这一次的竞争要求Microsoft(可以扩展到任何现存的软件公司)来成为一种在深入层面上显著有别的公司。天生的Web 2.0公司在享受自然而然的优势,因为它们不需要去摆脱陈旧的模式(及其相应的商业模式和营收来源)。

  5. 轻量型编程模型

  一旦网络服务的观念深入人心,大型公司将以复杂的网络服务堆栈来加入到纷争之中。这种网络服务堆栈被设计用来为分布式程序建立更可靠性的编程环境。

  但是,就像互联网成功正是因为它推翻了许多超文本理论一样,RSS以完美的设计来取代简单的实用主义,已经因其简单性而成为大概是应用最广泛的网络服务,而那些复杂的企业网络服务尚未能实现广泛的应用。

  类似地,Amazon.com的网络服务有两种形式:一种坚持SOAP(Simple Object Access Protocol,简单对象访问协议)网络服务堆栈的形式主义;另一种则简单地在HTTP协议之外提供XML数据,这在轻量型方式中有时被称为REST(Representational State Transfer,代表性状态传输)。虽然商业价值更高的B2B连接(例如那些在Amazon和一些像ToysRUs这样的零售伙伴之间的连接)使用SOAP堆栈,但是根据Amazon的报道,95%的使用来自于轻量型REST服务。

  同样的对简易性的要求,可以从其他“朴实的”网络服务中见到。Google近来的Google地图的推出就是一个例子。Google地图的简单AJAX(Javascript和XML的结合)接口迅速被程序高手们破译,被随即进一步将其数据混合到新的服务之中。

  地图相关网络服务已经存在了一段时间,例如像ESRI那样的GIS(地理信息系统),以及从MapQuest和Microsoft的MapPoint。但是Google地图以其简洁性而让世界兴奋起来。虽然从前销售商所支持的网络服务都要求各方之间的正式约定,但Google地图的实现方式使数据可以被捕获,于是程序高手们很快就发现了创造性地重用这些数据的方法。

  这里有几条重要的经验:

  1. 支持允许松散结合系统的轻量型的编程模型。由企业开发的网络服务堆栈的复杂设计是用来促成紧密结合的。虽然这在许多情况下是必须是,但是许多最重要的应用程序可以事实上保持松散结合,甚至是脆弱的结合。Web 2.0的理念同传统的IT的理念迥然不同。

  2. 考虑聚合(syndication)而不是协调(coordination)。简单的网络服务,例如RSS和基于REST的网络服务,是用来向外聚合数据,但并不控制其达到连接的另外一端时发生的事情。这种想法是互联网本身的基础,一种对所谓端到端原则的反映。

  3. 可编程性和可混合性设计。像最初的互联网一样,RSS和AJAX这样的系统,都有此共同点:重用的障碍非常低。许多有用的软件事实上是开放源码的,而即便它不是,也没有许多东西来保护其知识产权。互联网浏览器的“查看源文件”选项,使得许多用户可以复制其他任何用户的网页;RSS被设计得使用户能够在需要的时候查看所需要的内容,而不是按照信息提供者的要求;最成功的网络服务,是那些最容易采纳未被服务创建者想到的新的方向。同更普遍的“保留所有权利”(all rights reserved)相比,随着创作共用约定而普及的“保留部分权利”(Some Rights Reserved)一词成为一个有益的指路牌。

  装配中的创新

  轻量型商业模型是对轻量型编程和轻量型结合的一种自然产物。Web 2.0的理念善于重用。一种像housingmaps.com这样的新服务,是通过将两个现存服务抓取到一起来简单地创建起来的。Housingmaps.com还没有商业模式(目前为止),但对于许多小规模的服务,Google的AdSense(或Amazon的associates fees计划,或者两者都是)为同类服务提供了营收模式。

  这些案例为Web 2.0的另外一个关键原则提供了启发,我们将之称为“装配中的创新”。当商品组件充裕时,你可以通过以新颖的或者有效的方式来装配这些组件来创建价值。很像PC革命为硬件商品装配提供了许多创新的机会,其中像Dell这样的公司创造了这种装配的科学,并从而打败了那些商业模式上要求产品开发方面的创新的公司,我们相信Web 2.0为各个公司提供了,通过在利用和整合由其他人提供的服务方面逐渐完善,来赢得竞争的机会。

  6. 软件超越单一设备

  另外一个值得一提的Web 2.0特性是Web 2.0已经不再局限于PC平台这样一个事实。在对Microsoft的告别建议中,长期的Microsoft开发者戴夫·斯塔兹(Dave Stutz)指出:“超越单一设备而编写的有用软件将在未来很长一段时间里获得更高的利润”。

  当然,任何的网络程序都可被视为超越单一设备的软件。毕竟,即便是最简单的互联网程序也涉及至少两台计算机:一个负责网络服务器,而另一个负责浏览器。而且就如我们已经探讨过的,在将网络作为平台的开发中,把这个概念拓展到由多台计算机提供的服务而组成的合成应用程序中。

  但是如同Web 2.0的许多领域一样,在那些领域中“2.0版的事物”(2.0-ness)并不是全新的,而是对互联网平台真正潜能的一种更完美的实现,软件超越单一设备这一说法赋予我们为新平台设计程序和服务的关键性的洞察力。

  迄今为止,iTunes是这一原则的最佳范例。该程序无缝地从掌上设备延伸到巨大的互联网后台,其中PC扮演着一个本地缓存和控制站点的角色。之前已经有许多将互联网的内容带到便携设备的尝试,但是iPod/iTunes组合却是这类应用中第一个从开始就被设计用于跨越多种设备的。TiVo则是另外一个不错的例子。

  iTunes和TiVo也体现了Web 2.0的其他一些核心原则。它们本身都不是网络程序,但都利用了互联网平台的力量,使网络成为其体系中无缝连接的、几乎不可察觉的一部分。数据管理显然是它们所提供的价值的核心。它们也是服务,而非打包的程序(虽然对于iTunes来说,它可以被用作一个打包的程序来仅仅管理用户本地的数据)。不仅如此,TiVo和iTunes都展示了一些集体智慧的方兴未艾的应用。虽然对于每个情况,其实验都是同网络IP入口的周旋。iTunes中只有有限的参与体系,虽然近来增加的播客(podcasting)将这一规则规律性了不少。

  这正是我们希望看到伟大变革的Web 2.0领域中的一个,随着越来越多的设备正连接到这个新的平台中来。当我们的电话和汽车虽不消费数据但却报告数据时,可能会出现什么样的程序呢?实时的交通监测、快闪暴走族(flash mobs)、以及公民媒体,只不过是新平台的能力的几个早期警示。

  一篇Web 2.0的投资论文

  风险投资家保罗·科德罗斯基(Paul Kedrosky )写道:“关键在于去寻找一种你共识相左的,具有可操作性的投资”。有趣的是,我们注意到Web 2.0的每个方面都涉及到同共识的分歧:每个人都在强调保持数据隐私的重要性,而Flickr/Napster等等,却使其公开化。这并非只是为了分歧而分歧(比如追求宠物食在线),而是在可以从中创建出一些东西的地方发生分歧。Flickr缔造了社区,Napster创造了收藏的广度。

  另外一种看待这种现象的方式,就是成功的公司都放弃了一些昂贵但被认为重要的东西,以便免费获得一些有价值的曾经昂贵过的东西。例如,维基百科全书放弃了集中的编审控制,以作为对速度和广度的回报。Napster放弃了“目录册”的想法(列出所有销售商正在销售的歌曲),并因此获得了广度。Amazon放弃了用于一个实体店面的想法,却从而服务于整个世界。Google放弃了大宗用户(开始的时候),却得到了80%的,其要求从前未被满足的用户。下面的说法很有一些合气道(借力打力)的精神:“你知道,你是对的——整个世界的人都绝对可以更新这篇文章。而且你猜怎么着,这对你是个坏消息”。

  ——内森·托克英顿(Nat Torkington)

  7. 丰富的用户体验

  最早可以追溯到1992年魏裴(Pei Wei)开发的Viola浏览器,互联网就被用来在网页浏览器中传送“小程序”(applet)和其他一些活动内容。1995年Java的引入就是围绕着这样的小程序的传送。JavaScript和后来的DHTML都被作为轻量型方式引入,来为客户端提供可编程性和丰富的用户体验。几年以前,Macromedia缔造出“丰富的互联网应用程序”(Rich Internet Applications)一词(该词也被Flash的竞争者开放源码的Laszlo系统使用),以便凸显Flash不仅可传送多媒体内容,而且可以是GUI(图形用户界面)方式的应用程序体验。

  然而,互联网传递整个应用程序的潜能在Google引入Gmail之前,一直没有成为主流,紧接着就是Google地图程序,一些基于互联网的带有丰富用户界面以及PC程序等同的交互性的应用程序。在网络设计公司Adaptive Path的耶希•詹姆斯•加莱特(Jesse James Garrett)的一个讨论会论文中,Google所使用的这组技术被命名为AJAX。他写道:

  Ajax不是一项技术。它其实是几项技术,每项技术自身都很繁荣,它们以强有力的全新方式结合起来。Ajax涵盖:

  -- 运用XHTML和CSS实现基于各种标准的展示。

  -- 运用文档对象模型(Document Object Model)实现动态显示和交互。

  -- 运用XML和XSLT实现数据交换和操作。

  -- 运用XMLHttpRequest实现异步数据检索。

  -- JavaScript将所有这些绑定到一起。

  AJAX也是Web 2.0程序的一个关键组件,例如现在归属Yahoo!的Flickr,37signals的程序basecamp和backpack,以及其他Google程序,例如Gmail和Orkut。我们正在步入一个史无前例的用户界面创新阶段,因为互联网开发者们终于可以创建,像本地基于PC的应用程序一样丰富的网络程序了。

  有趣的是,许多现在正被探索的功能已经存在了很多年了。90年代后期,Microsoft和Netscape,都对现在终于被认识到的那些功能有所洞察,但是它们对于所要采用的标准的争斗,使得实现跨浏览器的应用程序变得困难。仅在当初Microsoft确定无疑地赢得了浏览器之战的时候,而且那时事实上只需要针对一个浏览器标准,编写这种程序才成为可能。同时,虽然Firefox在浏览器市场中重新引入了竞争,但至少在目前我们还没有看到对互联网标准的破坏性的争夺以至于我们倒退到90年代。

  在接下来的几年中,我们会看到许多新的网络程序,不仅确实是新颖的程序,而且是对PC程序丰富的网络再现。到目前为止,每个平台的变革也都为改变那些在旧平台中占主导地位的程序的领导地位创造了机会。

  Gmail已经在电子邮件中提供了一些有意思的创新,将互联网的力量(随处可访问、深层的数据库能力、可搜索性)与在易用性方面同PC界面接近的用户界面相结合。同时, PC平台上的其他邮件程序,正在从另一端通过增添IM和呈现能力,来蚕食着这一领域。我们离集成通信客户端有多少远呢?这些集成通信客户端应是整合了电子邮件、即时通信和手机,并且应使用VoIP以便向网络程序的丰富功能中添加语音能力。这种竞赛已经开始。

  我们也很容易看到Web 2.0是如何重新打造地址簿的。一个Web 2.0风格的地址薄将把PC或电话上的本地地址簿,仅仅当作一种你显式要求系统记忆的联系人的缓存。同时,一个基于互联网的Gmail风格的异步代理,将保存发送或者接收的每个消息,每个电子邮件地址和每个使用过的电话号码,并且创造出社交网络的启发性算法,来决定当一个答案不能在本地缓存中找到时,应该提供哪个作为替代。在缺少答案的情况下,该系统会查询更广阔的社交网络。

  一个Web 2.0的字处理程序将会支持维基风格的协作编辑,而不仅仅是处理独立的文档。但是该程序也会支持我们期望在基于PC的字处理器中得到的那种丰富格式。Writely是这种程序的一个优秀范例,虽然它尚未引起广泛关注。

  此外,Web 2.0革命不会局限于PC程序。例如,在CRM这样的企业级应用程序中,Salesforce.com展示了网络是如何被用来以服务的方式来传递软件的。

  对新的进入者来说,竞争机会在于充分开发Web 2.0的潜能。成功的公司将创建可以向其用户学习的程序,利用可供参与的体系来建立一种决定性的优势,不仅在软件的界面方面,而且在共享数据的丰富程度方面。

  Web 2.0公司的核心竞争力

  在探索上述七大原则的过程中,我们已经强调了Web 2.0的一些主要特性。我们探讨的每一个例子都体现着这些原则中的一个或多个,但是可能不满足其他的原则。因此,让我们通过总结我们认为是Web 2.0公司核心竞争力的一些方面,来结束本文。

  -- 服务,而不是打包的软件,具有高成本效益的可伸缩性。

  -- 控制独特的、难以再造的数据源,并且用户越多内容越丰富。

  -- 把用户作为共同开发者来信任。

  -- 利用集体智慧。

  -- 通过客户的自服务来发挥长尾的力量。

  -- 软件超越单一设备。

  -- 轻量型用户界面、开发模式、和商业模式。

  今后一个公司要宣称是“Web 2.0”,就要将其特性同上述列表相测试。越符合就越名副其实。不过要记住,在某一个领域的卓越表现,可能会比对七大原则中的每个都浅尝则止,要更为有效。

  Web 2.0的设计模式

  在“模式语言”(A Pattern Language)一书中,克里斯多夫?亚历山大(Christopher Alexander)为精炼描述对于体系结构问题的解决方案,开了一种格式上的处方。他写道:“每个模式都描述着一种在我们的环境中一遍又一遍地出现的问题,并因此描述了对该问题的核心解决方案。以此方式你可以使用该方案上百万次,而从不需要重复作同样的事情。”

  1. 长尾

  小型网站构成了互联网内容的大部分内容;细分市场构成了互联网的大部分可能的应用程序。所以,利用客户的自服务和算法上的数据管理来延伸到整个互联网,到达边缘而不仅仅是中心,到达长尾而不仅仅是头部。

  2. 数据是下一个Intel Inside

  应用程序越来越多地由数据驱动。因此:为获得竞争优势,应设法拥有一个独特的,难于再造的数据资源。

  3. 用户增添价值

  对互联网程序来说,竞争优势的关键在于,用户多大程度上会在你提供的数据中,添加他们自己的数据。因而,不要将你的“参与的体系”局限于软件开发。要让你的用户们隐式和显式地为你的程序增添价值。

  4. 默认的网络效应

  只有很小一部分用户会不嫌麻烦地为你的程序增添价值。因此:要将默认设置得使聚合用户的数据,成为用户使用程序的副产品。

  5. 一些权力保留

  知识产权保护限制了重用也阻碍了实验。因而,在好处来自于集体智慧而不是私有约束的时候,应确认采用的门槛要低。遵循现存准则,并以尽可能少的限制来授权。设计程序使之具备可编程性和可混合性。

  6. 永远的测试版

  当设备和程序连接到互联网时,程序已经不是软件作品了,它们是正在展开的服务。因此,不要将各种新特性都打包到集大成的发布版本中,而应作为普通用户体验的一部分来经常添加这些特性。吸引你的用户来充当实时的测试者,并且记录这些服务以便了解人们是如何使用这些新特性的。

  7. 合作,而非控制

  Web 2.0的程序是建立在合作性的数据服务网络之上的。因此:提供网络服务界面和内容聚合,并重用其他人的数据服务。支持允许松散结合系统的轻量型编程模型。

  8. 软件超越单一设备

  PC不再是互联网应用程序的唯一访问设备,而且局限于单一设备的程序的价值小于那些相连接的程序。因此:从一开始就设计你的应用程序,使其集成跨越手持设备,PC机,和互联网服务器的多种服务。

  奥莱理媒体公司(O'Reilly Media Inc.) 主席兼CEO 提姆·奥莱理(Tim O'Reilly)授权刊登,  美国密西根大学资深软件分析师玄伟剑提供全文翻译。

- 作者: GeorgeKong 2006年09月4日, 星期一 14:37  回复(0) |  引用(0) 加入博采

Web2.0创业:程序员的创业?
Web2.0创业:程序员的创业?
来自:Donews   邱致中

  “vini,vidi,vici? (我来了,我看到了,我征服了) ”
—— 凯撒大帝(公元前44年被刺死)

  上面这句话应当很符合当下正在激情澎湃中的创业团队的心境。今天我知道,说这句话的人当年何等意气风发,最后却并没有好死。似乎大多数打着Web2.0旗号的创业团队都是技术人员组成,我也是技术出身,所以觉得特别需要讨论一下由技术人员为主的创业团队的问题。

  A 无知者无畏,但可悲

  对于一个技术团队,典型的启动场景是这样:看到某个很火的网站,然后几个人一看就知道所有的技术应当如何来做(当然我们知道1万用户和1千万用户的系统作同样的事情的方式完全不同),于是就写了几个页面,觉得“我们也可以做!”。再然后,喝酒,上路……

  哥几个且慢,听我说一句。第一个问题就是:你运作(不是编码)过网站么?你知道需要哪些人、哪些资源才可以运作一个网站么?(如果你回答只需要找几个编辑云云,就无望了)这些事情你都没有做过,也没很好的去打听去学习去思考,就确定你可以搞定?13亿人有这雄心世界上早就只有一个国家了!

  如果还不知道你会面对什么,你需要解决什么问题,就去弄明白,成败不在这几天几周功夫。所有过来人都会告诉你,运作网站、创业需要如此如此多的资源以及考虑,技术只是小小的一块。那么在你上马之时,除了技术你还有什么?缺乏大部分的东西。

  B 切不可技术主导

  很自然,程序员来做必然技术主导。即使团队中有其他人,他们和他们的意见也会被边缘化(后面说这个问题)。如果我们要解决的问题是一个有确定需求的东西,目标只是技术上实现此系统,则这种方式绝无问题,甚至很专业。然而我们的目标是要设计(需求是不确定的并且会变化)一个东西,并且要运作他(不是运行它,非技术概念),就必须换一种思路和角度来考虑问题。特别是领导人,必须超脱于技术思维之上,否则最后的结果必然是“程序员们认为最好的东西”。

  C 思路的困顿,细节的羁绊

  我所常说的至上的细节主义,乃是对于设计的细节,而不是实现的细节,用任何方式实现所需要的细节效果即可,除了程序员不会有人关心实现细节。

  程序员可能就某个具体细节和实现方式认真地讨论半天并且重构你的系统,但是对于用户来说,这种修正对于使用没有任何值得一提的改善,价值几乎为0。所以不值得做这件事情,不过程序员不能接受不完美的解决方案,所以还是花了许多时间做一件没有意义的事情。

  程序员会拘泥于很多细节,本身不是坏事,但是当和用户关注的细节所错开时就麻烦了:你在做无用的改进,用户仍然在抱怨。当整个团队的思考重心都在技术上时,决策的偏向性会很明显,而且自己是无法察觉的。只有市场才会最终告诉你错了。

  D 无为才可无不为

  这个命题大了,本来与程序员无关,但是在程序员团队中特别严重。试问,倘若你是这个程序员团队的老大,你会去code么?你说会的,硅谷的所有酷公司的CEO都是亲自编码的,至少在起步阶段。

  第一,老大亲自编码并非成功必要条件,更不是充分条件。有点花絮性质;第二,那帮子家伙可是在做完了老大该做的事情后才去code的,要不然混不到今天。

  试问老大整天在code,谁去思考战略问题?谁去联络人脉和资源?这里无为的意思在于两层:第一层,你必须腾出时间和精力,才可以去思考,才可以去发现被忽视的问题,而这个不是非常重要,是“相当”的重要;第二层,你作为老大,去作具体的事情,作的不好没人怪你,做的决定没人提出异议……你有没有觉得味儿不对?

  那么,如何由技术人员成长为合格的老大?我不知道(不然可没功夫在这里扯淡,自嘲),只能给出几条参考的原则:

  1) 你不可以是技术领头人

  程序员通常会由资历最老、技术最好的人来当领导人,但是好像武林门派的掌门人未必是武功最高的吧,那种最牛鼻的,一般都隐藏在幕后,他们不适合作老大。

  我还不能透彻理解无为,但是值得大家去思考,因为我们都是中国人,这种文化硅谷是没有的。

  2) 提出要求和问题、引导解决,结论不可以由你给出

  刚才也提到了,你做错了没人可以批评,你说的一般没人反对,但是很多事情,你不能了解所有的信息(因为你不具体负责那块工作)但是你代替那个做事的人作出了具体决定,那么就有错误的可能。让每个人在各自的层面、各自的领域去思考去决定,你来管理所有的人才是正确的。你要做的就是看着整个军团的运作,思考还有什么没有想到的,指导某一块的改进,全都是隐性工作,所以不做也无所谓,所以总是被很多人忽视,所以失败者一定很多。

  3) 平衡团队中的小团队

  稍微有点见识的,一定会拉几个非技术的人入伙。但是更进一步的,你必须思考他们的定位。第一,老大也许不自觉的还是技术思维,而与他们讲不同的语言;第二,本来老大的亲信就是那群技术员。所以他们是孤立的边缘化的。但是在更高的角度看,技术应当是一小块,最为重要的是策划和运作。

  祝天下英雄早日功成名就!希望明年Donews英雄大会上多出几个真正的英雄,而且不是那种只能风光几年的小角色。

- 作者: GeorgeKong 2006年08月31日, 星期四 12:38  回复(0) |  引用(0) 加入博采

JDK1.5 - 泛型(Generics)

[转载]

1. 引言

JDK 1.5 中引入了新的语言成分, 泛型(Generics)是其中较为重要的一个.
简单的泛型(Defining Simple Generics)

以下代码摘自java.util包的List接口和Iterator接口的定义:

public interface List<E> {
  void add(E x);
  Iterator<E> iterator();
}
public interface Iterator<E> {
  E next();
  boolean hasNext();
}

类型参数

与尖括号有关的一些东西是JDK 5引入的新东西, 它们是List和Iterator接口的"形式的类型参数"(简称"类型形参")声明.
而在对泛型声明List进行调用时(例如: List<Integer>), 所有出现的类型形参(如
E)的地方, 都会被"实际的类型参数"(简称"类型实参", 如 Integer)所替换掉.

虽然与C++中的模板机制在形式上很想像, 但必需注意, Java中的泛型声明决不会在调用时被展成多份副本: 不论是在源码级, 二进制级, 还是在磁盘或内存中, 都不会被展开!

泛型声明只会也只需编译一次, 并生成一个类文件(class文件), 这一点跟普通的类或接口完全一样.

类型参数其实跟方法或构造器中所用的通常参数相类似. 一个方法中可以声明它用以处理的"形式的值参数", 相似地, 泛型声明也有其"形式的类型参数"; 当方法被调用时, 实际参数会替换形式参数, 然后执行方法体, 同样, 当泛型声明被调用时, 实际的类型参数会替换掉形式的类型参数.

关于命名约定的备注: 推荐使用精炼而简明(如, 单个字符)的方式为形式的类型参数命名. 最好避免使用小写字符, 以便与普通的类或接口的参数相区分开来. 许多宣传品类型使用 E 表示其元素的类型形参.


2. 泛类型与子类型化(Generics and Subtyping)

先看以下两行代码是否合法:
List<String> ls = new ArrayList<String>(); // 1
List<Object> lo = ls; // 2
第一行没问题, 关键在第二行代码, 大多数人会认为, "一个String的List自然更是一个Object的List", 因此, 第2行没问题.

好, 接着看以下代码:
lo.add(new Object()); // 3
String s = ls.get(0); // 4: 试图将一个Object赋给一个String!

可见, 通过别名lo, 我们能对ls, 一个String的列表, 进行数据操作(特别是插入一个Object), 从而导致ls不仅仅是容纳了String对象! 这是Java编译器不容许的! 编译时, 第2行会报告一个编译错误的.

通常, 若Foo是Bar的一个子类型(子类或子接口), G是某个泛型声明, 则G<Foo>并不是G<Bar>的一个子类型.

这一点往往是最难以理解的, 因为它和通常的直观相左. 在直观的理解中, 我们实际上假定了集合是不会变动的, 但java语言中则非如此.


3. 通配(Wildcards)

假定要输出一个集合中的所有元素. 以下分别是旧版本及新版本(JDK 1.5)中的写法:

void printCollection(Collection c) {
  Iterator i = c.iterator();
  for( k = 0; k < c.size(); k++) {
    System.out.println( i.next() );
}}

void printCollection(Collection<Object> c) {
  for(Object e : c) {
    System.out.println(e);
}}

问题在于, 新版本反而不如旧版本更有用些. 因为旧版本能使用各种类型的集合作为参数, 但新版本则只能使用Collection<Object>. 而正如上节看到的, Collection<Object>并不是其它各种集合的超类型(父类型).

所有集合的超类型应该写作: Collection<?>, 读作: collection of unknown(未知集合), 即一个集合, 其元素类型可以与任何类型相匹配. 因此称这种类型为"通配类型".

正确实现上述旧版本的代码可以这么写:
void printCollection(Collection<?> c) {
  for(Object e : c) {
    System.out.println(e);
}}

这时, 可以用任意类型的集合来调用此方法. 注意在方法体中, 仍然从 c 中读入元素并赋给了Object, 这是没有错误的, 因此不论类型实参是何种集合, 它的元素都是object. 然而, 如果任意给它增加一个object则是不安全的:

Collection<?> c = new ArrayList<String>();
c.add(new Object()); // 编译时的错误

由于我们不知道c的元素类型是什么, 所以不能给它增加一个object. 方法add()接受一个类型E的参数, 而E与集合的元素类型相同. 当类型实参是?时, 它表示"未知的类型", 我们传递给add的参数必须是这个"未知类型"的子类型. 不幸的是, 既然类型未知, 也就无法决定其子类型, 于是什么也不能作为其参数. 唯一的例外是null, 因为null是所有类型的一个成员.

另一方面, 如果给了一个List<?>, 我们可以调用get()方法并使用其返回的元素. 虽然返回的元素类型是"未知类型", 但它总归是一个object, 因此将get()返回的元素赋给一个Object类型的变量, 或将其传递给一个可接受Object的参数都是安全的.

- 作者: Kiash 2006年08月16日, 星期三 14:52  回复(0) |  引用(0) 加入博采

JDK1.5 - 枚举类型

[转载]

  Enum作为Sun全新引进的一个关键字,看起来很象是特殊的class, 它也可以有自己的变量,可以定义自己的方法,可以实现一个或者多个接口。 当我们在声明一个enum类型时,我们应该注意到enum类型有如下的一些特征。

  1.它不能有public的构造函数,这样做可以保证客户代码没有办法新建一个enum的实例。

  2.所有枚举值都是public , static , final的。注意这一点只是针对于枚举值,我们可以和在普通类里面定义 变量一样定义其它任何类型的非枚举变量,这些变量可以用任何你想用的修饰符。

  3.Enum默认实现了java.lang.Comparable接口。

  4.Enum覆载了了toString方法,因此我们如果调用Color.Blue.toString()默认返回字符串”Blue”.

  5.Enum提供了一个valueOf方法,这个方法和toString方法是相对应的。调用valueOf(“Blue”)将返回Color.Blue.因此我们在自己重写toString方法的时候就要注意到这一点,一把来说应该相对应地重写valueOf方法。

  6.Enum还提供了values方法,这个方法使你能够方便的遍历所有的枚举值。

  7.Enum还有一个oridinal的方法,这个方法返回枚举值在枚举类种的顺序,这个顺序根据枚举值声明的顺序而定,这里Color.Red.ordinal()返回0。

  了解了这些基本特性,我们来看看如何使用它们。

  1.遍历所有有枚举值. 知道了有values方法,我们可以轻车熟路地用ForEach循环来遍历了枚举值了。

for (Color c: Color.values())
System.out.println(“find value:” + c);

  2.在enum中定义方法和变量,比如我们可以为Color增加一个方法随机返回一个颜色。

public enum Color {
 Red,
 Green,
 Blue;

 /*
 *定义一个变量表示枚举值的数目。
 *(我有点奇怪为什么sun没有给enum直接提供一个size方法).
 */
 private static int number = Color.values().length ;

 /**
 * 随机返回一个枚举值
 @return a random enum value.
 */
 public static Color getRandomColor(){
  long random = System.currentTimeMillis() % number;
  switch ((int) random){
   case 0:
    return Color.Red;
   case 1:
    return Color.Green;
   case 2:
    return Color.Blue;
   default : return Color.Red;
  }
 }
}

  可以看出这在枚举类型里定义变量和方法和在普通类里面定义方法和变量没有什么区别。唯一要注意的只是变量和方法定义必须放在所有枚举值定义的后面,否则编译器会给出一个错误。

  3.覆载(Override)toString, valueOf方法

  前面我们已经知道enum提供了toString,valueOf等方法,很多时候我们都需要覆载默认的toString方法,那么对于enum我们怎么做呢。其实这和覆载一个普通class的toString方法没有什么区别。

….
public String toString(){
 switch (this){
  case Red:
   return "Color.Red";
  case Green:
   return "Color.Green";
  case Blue:
   return "Color.Blue";
  default:
   return "Unknow Color";
 }
}
….

  这时我们可以看到,此时再用前面的遍历代码打印出来的是

Color.Red
Color.Green
Color.Blue

  而不是

Red
Green
Blue.

  可以看到toString确实是被覆载了。一般来说在覆载toString的时候我们同时也应该覆载valueOf方法,以保持它们相互的一致性。

  4.使用构造函数

  虽然enum不可以有public的构造函数,但是我们还是可以定义private的构造函数,在enum内部使用。还是用Color这个例子。

public enum Color {
 Red("This is Red"),
 Green("This is Green"),
 Blue("This is Blue");

 private String desc;

 Color(String desc){
  this.desc = desc;
 }

 public String getDesc(){
  return this.desc;
 }

}

  这里我们为每一个颜色提供了一个说明信息, 然后定义了一个构造函数接受这个说明信息。

  要注意这里构造函数不能为public或者protected, 从而保证构造函数只能在内部使用,客户代码不能new一个枚举值的实例出来。这也是完全符合情理的,因为我们知道枚举值是public static final的常量而已。

  5.实现特定的接口

  我们已经知道enum可以定义变量和方法,它要实现一个接口也和普通class实现一个接口一样,这里就不作示例了。

  6.定义枚举值自己的方法。

  前面我们看到可以为enum定义一些方法,其实我们甚至可以为每一个枚举值定义方法。这样,我们前面覆载 toString的例子可以被改写成这样。

public enum Color {
 Red {
  public String toString(){
   return "Color.Red";
  }
 },
 Green {
  public String toString(){
   return "Color.Green";
  }
 },
 Blue{
  public String toString(){
   return "Color.Blue";
  }
 };
}

  从逻辑上来说这样比原先提供一个“全局“的toString方法要清晰一些。

  总的来说,enum作为一个全新定义的类型,是希望能够帮助程序员写出的代码更加简单易懂,个人觉得一般也不需要过多的使用enum的一些高级特性,否则就和简单易懂的初衷想违背了。

- 作者: GeorgeKong 2006年08月16日, 星期三 14:30  回复(0) |  引用(0) 加入博采

Sun的移动信息设备框架(MIDP)主页

移动信息设备框架(MIDP)
 最新MIDP下载 
 

MIDP 2.0

MIDP 1.0


 
Mobile Information Devices

MIDP 2.0 最终版本实施参考(RI) 现在就提供下载!
小窥 | MIDP的创新点

下载J2ME无线开发包2.0 下在就开始MIDP 2.0应用!

移动信息设备框架(MIDP)和连接有限设备配置(CLDC), 一起为现今的移动信息设备(MID),如电话和入门级PDA,提供Java运行环境。MIDP提供的是,移动应用必需的核心部件,包括---用户界面、网络连通性、局部数据存储和生命周期应用管理包---一个标准的Java运行环境的API。

MIDP规范以由Java社区进程,一个专家组织,由设备厂商、 无线工作者及软件工作人员组成,所编辑完成。

Downloads

MIDP规范最新文档

MIDP 2.0

  • MIDP RI 2.0: 这个版本的MIDP实施参考是以MIDP 2.0规范为基础,支持CLDC RI 1.0.4。此MIDP RI可针对那些,想移植这个J2ME框架到另外的平台的设备厂商。
  • CLDC RI 1.0.4: 此版本的CLDC实施参考是基于CLDC 1.0规范,并可针对那些想移植这个J2ME配置到另一平台的设备厂商。
  • J2ME无线开发包2.0: 这个最终版结合主流技术---完整开发环境(IDE),对MIDP 2.0开发应用提供完整的开发支持。

MIDP 1.0

  • MIDP RI 1.0.3: 这个版本的MIDP实施参考是基于MIDP 1.0规范,支持CLDC RI 1.0.3。此MIDP RI可针对那些,想移植这个J2ME框架到另外的平台的设备厂商。 
  • CLDC RI 1.0.3: 此版本的CLDC实施参考是基于CLDC 1.0规范,并可针对那些想移植这个J2ME配置到另一平台的设备厂商。
  • MIDP Palm OS 1.0版: 它基于CLDC 1.0和MIDP 1.0规范,最优化提供Palm OS平台J2ME实施
  • J2ME无线开发包: 1.0.4版结合先进主流IDE支持开发MIDP 1.0应用。
  • MIDP 1.0风格介绍: 所用章节现在全都可看了! 引领开发者针对市场,去设计合适的MIDlet。

兼容性工具包 (TCK): MIDP TCK可通过Sun技术认证后用于特殊平台。预知更多认证信息,请访问Sun的Java合作伙伴组织

Support

常见问题:常见问题中找寻更多的MIDP。

Java平台支持引擎:查询关于Java合作伙伴组织,为J2ME嵌入式移动信息设备框架(MIDP)用户提供的帮助。告知新的无线Java设备的解决方案。请访问Java合作伙伴组织:http://www.sun.com/software/jpe

社区支持: 在MIDP和最新的J2ME技术上交换意见和建议的KVM-INTEREST邮件列表。

无线开发入门:入门的技术文章、教程、例程和其它。

系列产品: 寄来你的问题, 关于MIDP 的意见和反馈请寄至midp-comments@sun.com

Sun专家支持事项: Sun提供大量java2平台技术支持,更多事项请参见在线支持

- 作者: GeorgeKong 2005年12月16日, 星期五 12:20  回复(0) |  引用(0) 加入博采

MIDP 2.0 开发J2ME游戏教程

文章简介:  用GameCanvas类处理Graphics对象  本节中,我将介绍Graphics对象类在游戏中被应用的主要方面。在Tumbleweed游戏中,我...

    用GameCanvas类处理Graphics对象

  本节中,我将介绍Graphics对象类在游戏中被应用的主要方面。在Tumbleweed游戏中,我要画一个穿越草原的牛仔。在设计中,我将玩家的得分情况显示在屏幕底端,而游戏时间显示在顶端(为使样例不至太过复杂,我仅仅在玩家使用玩规定的时间后才自动终止游戏)。因为牛仔独自在走,我的想法是让他的背景向右或者向左滚动(否则在这个狭小的屏幕上他好象根本没走多远),而时间和分数的显示不动。
为了实现这个设计,我用JumpCanvas类来画屏幕顶端和底端稳定不动的显示条,而动态有趣的图形是用LayerManager类来实现的。
  JumpCanva类创建时,你必须先分析要使用的显示屏幕。有一些显示屏幕信息来源于Graphics对象,一些来自于display对象,还有一些直接来源于GameCanvas类的方法。这些信息用来计算对象应当显示的位置,包括计算显示区域的尺寸,LayerManager子类(JumpManager)将在这些区域重复显示对象。如果你坚持维护Java“一处写就,处处运行”的特性,基于动态屏幕尺寸而不是基于常量尺寸设置屏幕显示区域显然更方便合理。

  当然,如果从一种目标显示设备转向另一种游戏需要巨大的代码更改量,显然应该根据不同设备显示维护多个游戏版本,运行时根据显示设备信息调用游戏的不同版本,而不是将所有代码置于一个版本中。

  在样例游戏中,如果实际显示的设备与游戏中定义的显示设备差别太大,将有一个异常抛出以便Jump类捕获并且显示警告给玩家。为了显得更专业,你应当确保给玩家的警告信息明确标明他针对当前的设备应该下载的版本号。

  也许有点多余,但我后面仍然会告诉大家我认为顶端和底端区域合适的尺寸,paint(Graphics g)方法将描绘出顶端的白色和底端的绿色,g.drawString()方法用来记录使用的时间和分数。(不用问我为什么游戏的草原中都是颜色相同的绿草和风滚草;唯一的解释是我对Java的了解当然远甚于西部荒原。)

  LayerManager类

  一个MIDP游戏中富有乐趣的图形对象常常是用javax.microedition.lcdui.game.Layer类的子类来展示。背景层是javax.microedition.lcdui.game.TiledLayer的实例化,游戏的主人公(和他的敌人)是javax.microedition.lcdui.game.Sprite的实例,这两个类都是Layer的子类。LayerManager类用来组织所有的图形对象层,追加你的图层对象到管理器LayerManager的顺序,决定了他们运行时被描绘的次序(后进先出,最先追加的最后显示)。规则是上面的图层将覆盖下面的图层,不过你可以通过创建包含透明区域的图象文件(上层)来部分地显示下层图层中你想要的部分。

  LayerManager类实际中最有用的也许是你可以创建一个远大于显示屏幕的图形对象,然后选择它将在屏幕中被显示的部分显示出来。你可以想象事先做出一幅巨大的、精心描绘的图画,然后用一张纸去覆盖它,而纸上有一个方孔在图画上自由移动。巨幅的整张图画代表你保存在LayberManager中的显示信息,而方孔是任一给定时刻在屏幕上显示图画的窗口。游戏代码设计中,一个比实际屏幕大得多的虚拟显示屏幕对于通常运行在小屏幕显示设备上的游戏是极其重要的,它将为你节省大量的时间和工作。

  举个例子,比如你的游戏中包含主人公在一个复杂的地牢中摸索前进的场景,最麻烦的是你必须处理两个独立坐标系统。GameCanva的图形对象有一个坐标系,但是根据LayerManager坐标系的要求,图形中的不同图层又需要被置于LayerManager中。所以,一定要牢记LayerManager.paint(Graphics g, int x, int y)方法根据GameCanvas的坐标系在屏幕上描绘图层,而LayerManager.setViewWindow(int x, int y, int width, int height)方法根据LayerManager坐标系的要求设置LayerManager的可视矩形的显示属性。

  在样例中,我设计了一个简单的背景(仅仅是一系列重复显示的草丛),但我想让牛仔从右向左行走的时候总是显示在屏幕中央,所以我需要不断改变LayerManager的图形可显示区域。这项工作是通过在LayerManager的子类JumpManager类中方法paint(Graphics g)中调用setViewWindow(int x, int y, int width, int height)方法完成的。更准确地说,逻辑是这样的:GameThread中的主循环调用JumpCanvas.checkKeys()来检查按键状态,并且通知JumpManager类牛仔此时应该向左、向右还是应该跳跃了。JumpCanva类通过调用setLeft(boolean left)或者jump()方法将信息传至JumpManager。如果信息表明牛仔此时应该向左走(向右与之类似),那么当GameThead调用JumpCanvas告诉JumpManager继续的时候(循环的下一步),JumpManager就告诉牛仔对象向左移动一个象素,同时通过向左移动视窗一个象素来保持牛仔在屏幕中央。你可以通过增加字段myCurrentLeftX的值(这个作为X坐标值传至setViewWindow(int x,int y,int width,int height)),接着调用myCowboy.advance(gameTicks, myLeft)来实现这两个动作。

  当然,我可以不移动牛仔,也不把他追加到LayerManager,而只是独立地描绘他,这样也可以确保牛仔在屏幕中央。但显然通过将所有的移动对象置于相对静止的一系列图层中然后将视窗集中在牛仔对象上,借此保持所有对象的运动轨迹的方法要更容易。在通知牛仔前进的同时,风滚草对象Sprites和青草对象TiledLayer也也同时移动,然后检测牛仔是否被风滚草撞倒(在以下章节里我将说明实现这个功能的更多细节)。在移动了所有游戏对象后,JumpManager类调用wrap()方法来检查是否前端窗口到达了背景窗口的边缘,如果是,移动所有的有些对象以便视窗能继续在任一方向无限显示,接着JumpCanvas类重画每一个对象,再次执行游戏主循环。

  Wrap()方法需要多说几句。很不幸,如果你想让你的简单背景不确定地重复显示,LayerManager类并不提供现成的隐藏方法. 当传至方法setViewWindow(int x, int y, int width, int height)的坐标参数值大于Integer. MAX_VALUE 时,LayerManager的图形区域将被隐藏,但这似乎对我们的想法没有任何帮助。因此,你必须写自己的函数来避免牛仔Sprite对象离开背景区域。

  样例中,背景草丛总是在间隔数值Grass.TILE_WIDTH*Grass.CYCLE后被重画,所以任何时候视窗的X坐标值(myCurrentLeftX)都是背景图形宽度的整数倍。这样每次重画时,我都可以将视窗移回到显示中心,并且同时在相同的方向上移动Sprites对象,这样显然能平滑地阻止牛仔到达背景边界。

  Listing 4 JumpManager.java.

package net.frog_parrot.jump;

import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;

/**
* This handles the graphics objects.
*
* @author Carol Hamer
*/
public >:

- 作者: GeorgeKong 2005年12月16日, 星期五 12:19  回复(0) |  引用(0) 加入博采

详解MIDP 2.0生命周期程序设计 (1)

尽管支持移动信息设备规范MIDP 1.0的手机大量地出现在市面上,不管是Nokia未来发售的各款手机,还是Motorola T720、V60i,Sony Ericsson P800等手机,每一款都支持MIDP 1.0。但是,Sun也没忘记继续和各家手机厂商制定下一代Java手机的规格—MIDP 2.0。

何谓应用程序管理员


应用程序管理员在规格中也称作Application Management Software。这是一个用来执行J2ME应用程序的程序,它负责管理该装置上所有的J2ME应用程序。

应用程序管理员的设计方式会随着平台的不同而不同,但是大致上可以分成两种方式:

1. 在背后运作,使用者不知道应用程序管理员的存在。这种类型的应用程序管理员概念如图1所示。



图1 背后运作的应用程序管理员


背后运作的应用程序管理员的设计方式,使得一般的J2ME程序看起来和应用程序管理员一样,即使实际上应用程序管理员在背后运作,使用者也很难感受到。这种设计可以在MIDP for Palm之中看到,Java HQ就是这样的东西,如图2所示。



图2 Java HQ


但是,如果是程序开发者一旦安装了Developer.prc,仍然可以透过Java HQ之中的Developer Preference里的MIDlets按钮来观察整个系统之中所安装的每一个Java应用程序。

2. 一个单一的进入点,使用者必须先进入应用程序管理员,然后才能启动个别的Java应用程序。这种类型的应用程序管理员概念如图3所示。



图3 单一进入点的应用程序管理员


这种应用程序管理员设计可以在Motorola A388、Nokia 9210、Nokia 7650的手机上看到。

JAD与JAR


一个完整的MIDP应用程序是由一个JAD文件(纯文字文件)与JAR(ZIP压缩档)所组成。JAD与JAR之间的关系可以用图4简单描述。之所以有这样的设计,主要为了下面两个原因:



图4 JAD与JAR关系图


1. 网络传输费用;

2. 安全性。

MIDP 2.0之后,为了保护JAR不受窜改,同时也让安装程序的人可以确定MIDlet的来源,所以特别增加了安全设计如图5。



图5 安全设计JAD图


其中,MIDlet-Jar-RAS-SHA1属性值为经过base64编码的执行文件数字签章。而MIDlet-Certificate-<n>-<m>属性值为安全证明。在MIDlet安装前,应用程序管理员会使用安全证明来验证公开金钥的可靠性,然后再使用此公开金钥解开数字签章,确认此执行档的来源并确定没有受到非法窜改。

最后请注意,并非每种装置在安装时都要求同时有JAD与JAR,有些装置只需要JAR即可。不过,有JAD和没有JAD的J2ME应用程序在安全性上是有差异的。

MIDP执行环境


根据MIDP规格,所谓MIDP执行环境(MIDP Execution Environment)指的是下面几项所构成的集合:

1. 实作CLDC中所定义的类别函数库的类别档(以Java撰写)及原生程序(Native code,以C撰写)。MIDlet Suite里不能有与CLDC类别函数库同样名称的类别;

2. 实作MIDP中所定义的类别函数库的类别档(以Java撰写)及原生程序(Native code,以C撰写)。MIDlet Suite里不能有与MIDP类别函数库同样名称的类别;

3. 所有来自同一个JAR档中的类别档。包括设计者自己所撰写的类别、其它的JSR(例如Profile或Optional Package),或其它开放的函数库(例如kXML或kSOAP);

4. 所有来自同一个JAR档之中的非类别档(即资源文件),另外,记录管理系统(RMS,MIDP版的数据库管理系统)也是可共享的资源之一;

5. 权限确认与连结外部资源;

6. 描述文件与清单文件的内容。

以上这几点构成所谓的MIDP执行环境。应用程序管理员会保证这些资源都可以在执行时期供MIDlet存取。而且,位于同一个MIDlet Suite的MIDlet会共享同一组MIDP执行环境,并且可以彼此互动。MIDlet可以调用CLDC的类别函数库,也可以调用MIDP的类别函数库,如图6所示。



图6 MIDlet执行环境图


只有存取标准CLDC与MIDP函数库的MIDlet Suite才可以跨平台。通常手机厂商会针对自己的装置开发专属的API,例如Nokia的UI API、SMS API、Camera API。一旦程序使用了这些专属API,那么除非其它厂商也在其虚拟机器之中实作这些API,否则很难达到跨平台的目的。

功能与资源


位于JAR档之中的类别档可以被同一个JAR档之中的MIDlet所使用。同一个JAR档里的资源档可以透过java.lang.Class.getResourceAsStream()来存取。描述档的内容则可以透过javax.microedition.mdilet. MIDlet.getAppProperty()取得,如图7所示。



图7 JAR功能资源图
使用getResourceAsStream()时,必须给定一个URL,由于我们要存取JAR内部的资源,如果使用「/」作为开头,代表绝对路径,「/」代表JAR文件之中的根目录。如果没有使用「/」,则视为相对路径,要看调用getResourceAsStream()类别的所在路径而定,这样容易造成混淆。所以请尽量使用「/」作为开头的绝对路径。

MIDlet的程序结构


如果曾经撰写过Java Applet或Java Servlet,就知道制作Java Applet,必须继承自java.applet.Applet这个类别;制作Java Servlet,则程序必须继承自javax.servlet. http.HttpServlet这个类别。同理,要撰写能够在手机上执行的Java MIDlet必须要继承自javax.microedition.midlet. MIDlet类别,如图8所示。



图8 MIDlet继承体系图


javax.microedition.midlet.MIDlet类别中定义了三个抽象方法,它们分别是:startApp() ==> 至运作状态;pauseApp() ==> 至停止状态;destoryApp() ==> 至消灭状态。应用程序管理员就是透过这三个抽象方法来控制MIDlet的生命周期。因此,所有的MIDlet都必须实现这三个方法,才保证能正常运作。因此,一个MIDlet的程序外壳至少要如下:

import javax.microedition.midlet.*;
public class HelloMIDlet extends MIDlet
{
 public HelloMIDlet() 
 {
  //建构式
 }
 public void startApp() 
 {
 }
 public void pauseApp() 
 {
 }
 public void destroyApp(boolean unconditional) 
 {
 }
}


根据MIDP规格,MIDlet中不应该有“public static void main(Straing[] args)”这个方法。如果有则应用程序管理员会忽略不管。

一旦MIDlet被JAM载入之后,首先会先呼叫MIDlet中没有参数的建构式以进行初始化的工作。如果熟悉Java语法一定知道Java语言的一些特性,就是如果没有在程序中加入任何建构式,编译器会自动帮助加入一个预设建构式。但是如果已经撰写了自己的建构式(有任何参数),那么编译器将不会自动帮助加上预设建构式。因此,如果有必要撰写有参数的建构式,别忘了再手动加上一个没有参数的建构式,否则MIDlet将无法正确地初始化。

MIDlet的起始行为


当MIDlet被应用程序管理员产生之后,MIDlet就开始运作,程序设计师应该做的事情如图9所示。



图9 MIDlet起始行为图


我们会使用Display.getDisplay(this)来取得代表该MIDlet显示屏的Display对象。从应用程序管理员呼叫startApp()到MIDlet结束运作这段时间之内,不管何时呼叫Display.getDisplay(this),取得的都是同一份Display对象的参考。

要设定显示在屏幕上的画面,会使用Display对象的参考,并调用其setCurrent()方法,即display.setCurrent( Displayable类别的子类别实体)。因此一个可以运作的MIDlet程序,至少如HelloMIDlet.java,代码为:

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class HelloMIDlet extends MIDlet
{
 private Display display;	
 public HelloMIDlet() 
 {
  display = Display.getDisplay(this);
 }
 public void startApp() 
 {
  Form t = new Form("画面");
  display.setCurrent(t);
 }
 public void pauseApp() 
 {
 }
 public void destroyApp(boolean unconditional) 
 {
 }
}


注意:根据规格MIDlet只能由应用程序管理员产生,我们不能自己在程序里生成其它的MIDlet,并呼叫其生命周期函数,这样做将引发SecurityException异常。

MIDlet的生命周期


前面简单地叙述了应该如何撰写一个MIDlet的轮廓。但事实上,MIDlet的运作稍微复杂一点。所以接下来要仔细探讨MIDlet的运作细节,也就是MIDlet的生命周期。

当MIDlet被应用程序管理员成功地初始化之后,就开始展开了它的生命周期。图10描述了一个MIDlet的生命周期。MIDlet的生命周期完全由应用程序管理员控制,也就是说,当MIDlet要从一个状态变成另外一个状态时,应用程序管理员会呼叫对应的回呼函数(Call Back,也就是MIDlet类别定义的那三个抽象方法)。MIDlet基本上有三种状态,分别是停止状态(Paused)、启动状态(Active)及毁灭状态(Destroyed)。MIDlet开始时一定是先进入停止状态,然后应用程序管理员再将它转换成启动状态,然后调用startApp(),见图10。只有当应用程序管理员认为MIDlet的状态必须改变时,才会呼叫图中的相关函数。



图10 MIDlet生命周期图
以Active状态来说,MIDlet先进入运作状态,然后才调用startApp(),而MIDlet会先调用pauseApp()或destroyApp(),然后再进入停止状态和毁灭状态,这就是之所以Active没有被动式(字尾没有加ed),而Paused和Destroyed都是被动式(字尾有加ed)的真正涵义。

如果MIDlet自己调用这些函数,通常不会发生错误(除非程序本身有逻辑上的错误),但是也不会造成状态的转换,只是一个单纯的函数呼叫而已。如果MIDlet在状态转换回呼函数执行时发生错误,那么就应该丢出MIDletStateChange Exception异常,让应用程序管理员知道该如何处理。

请使用下列程序HelloMIDlet.java代码来验证MIDlet的生命周期:

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class HelloMIDlet extends MIDlet
{
 private Display display;	
 public HelloMIDlet() 
 {
  System.out.println("Constructor") ;
  display = Display.getDisplay(this);
 }
 public void startApp() 
 {
  System.out.println("startApp Called") ;
  Form t = new Form("画面");
  display.setCurrent(t);
 }
 public void pauseApp() 
 {
  System.out.println("pauseApp Called") ;
 }
 public void destroyApp(boolean unconditional) 
 {
  System.out.println("destroyApp Called :" + unconditional) ;
 }
}


执行结果时我们会在讯息显示窗口看到:

Constructor
startApp Called


此结果表示建构式先被呼叫,然后startApp()才会呼叫。

这时如果我们按下强制关闭应用程序的按钮 ,屏幕上就会出现:

destroyApp Called :true


这代表当我们使用装置上的按钮强制关闭MIDlet时,应用程序管理员会调用destroyApp(),并传入true作为参数。因此,撰写程序时,可以假定destroyApp()传入true时,是硬件强制关闭MIDlet的情形。

从图10中可以看出,startApp()很可能不只是被呼叫一次,而是每次从停止状态重新回到运作状态的时候都会被应用程序管理员调用,所以只需要被初始化一次的动作就不适合放在startApp()之中,请改用建构式做初始化动作。如果startApp()丢出MIDletStateChangeException或RuntimeException或两者的子类别,那么会立刻进入毁灭状态,而且系统会自动调用destroyApp(true)。

由于规格告诉我们,startApp()的执行时间应该尽可能短。如果程序在执行时,发生的错误是可以稍候就解决的(很可能是系统资源暂时不足),那么程序设计师就该直接丢出MIDletStateChangeException。拦截之后,再调用notifyPaused(),稍待一会再藉由异步事件呼叫resumeRequest(),重新试看看。如果发生错误即使稍待一会也无法解决,那么程序设计师就应该直接调用notifyDestroyed()来结束程序。参见如下代码:

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class HelloMIDlet extends MIDlet
{
 private Display display;	
 public HelloMIDlet() 
 {
  System.out.println("Constructor") ;
  display = Display.getDisplay(this);
 }
 public void startApp() 
 {
  System.out.println("startApp Called") ;
  Form t = new Form("画面");
  display.setCurrent(t);
  throw new RuntimeException() ;
 }
 /*
 public void startApp() throws MIDletStateChangeException
 {
  System.out.println("startApp Called") ;
  Form t = new Form("画面");
  display.setCurrent(t);
  throw new MIDletStateChangeException() ;
 }
 */
 public void pauseApp() 
 {
  System.out.println("pauseApp Called") ;
 }
 public void destroyApp(boolean unconditional) 
 {
  System.out.println("destroyApp Called :" + unconditional) ;
 }
}


执行结果如下:

Constructor
startApp Called
startApp threw an Exception
java.lang.RuntimeException
java.lang.RuntimeException
	at HelloMIDlet.startApp(+33)
	at javax.microedition.midlet.MIDletProxy.startApp(+7)
	at com.sun.midp.midlet.Scheduler.schedule(+266)
	at com.sun.midp.main.Main.runLocalClass(+28)
	at com.sun.midp.main.Main.main(+88)
destroyApp Called :true


一般来说,应用程序管理员会因为某些状况必须请MIDlet停止运作,例如手机突然来电、闹铃响了或者使用者切换到其它程序执行。在这些情况下,为了避免MIDlet占用太多系统资源,应用程序管理员就会调用该MIDlet的pauseApp()。这样程序设计师应该在pauseApp()之中适时释放一些非必需的资源,等到回到运作状态时,应用程序管理员会重新呼叫startApp(),这时再将这些之前被pauseApp()释放的资源重新找回来。
当MIDlet进入停止状态时,不应该使用任何资源。如果应用程序管理员调用pauseApp()时产生例外情形,MIDlet就应该立刻进入毁灭状态。

同样的情况也发生在destroyApp()。通常此方法被调用的时候,代表MIDlet要被关闭了,所以程序设计师应该在这里释放自己所配置的资源。只要MIDlet进入了毁灭状态,就无法再回头。如果是系统自己调用destroyApp(),那么在destroyApp()执行时万一发生例外,这些例外将被忽略,MIDlet一样会被关闭。根据规格,我们不能在MIDlet之中直接呼叫System.exit()或Runtime.exit()来结束程序的执行。如果这样做,就会引发java.lang.SecurityException异常。

MIDlet管理自己的生命周期


除了由应用程序管理员来控制MIDlet的生命周期之外,MIDlet本身也可以决定自己的状态,但不是自己改变状态,而是MIDlet先呼叫上述相对应的状态改变函数。这些函数会发出讯息通知应用程序管理员,请它来帮助改变MIDlet的状态,但是决定权在应用程序管理员,不保证一定可行。状态改变函数如图11所示:



图11 MIDlet状态改变函式图


对照以上这两张与状态有关的图,举个例子大家可能会比较清楚:假设今天如果是MIDlet主动要将MIDlet的状态由运作状态变成停止状态,那么直接呼叫pauseApp()函数只会执行pauseApp()之中的程序代码,而无法改变MIDlet的状态。MIDlet必须呼叫notifyPaused()以通知应用程序管理员,应用程序管理员收到通知之后,才会让MIDlet进入停止状态。

不过,由MIDlet调用notifyPaused()与应用程序管理员主动要求停止,两者之间是有所差别的。它们主要在于应用程序管理员主动要求停止时,pauseApp()会被呼叫,而由MIDlet调用notifyPaused(),pauseApp()不会被调用。但是两者都会让MIDlet进入停止状态。所以在MIDlet调用notifyPaused()之前,最好自己也先调用pauseApp()比较适当。

同样的情况也发生在notifyDestroyed()与destroyApp()。除非是系统强制关闭MIDlet,否则最好MIDlet先呼叫destroyApp(),然后再呼叫notifyDestroyed()。请应用程序管理员帮助将MIDlet转换到毁灭状态,最后结束MIDlet的运作。单单MIDlet自己呼叫destroyApp()是没有用的。

destroyApp()有个布尔值作为参数,根据MIDP的规格,如果传入true,那么MIDlet不管如何应该无条件释放所有资源,然后让应用程序管理员结束MIDlet的运作,这是系统或硬件强制关闭MIDlet的情形。如果使用者调用notifyDestroyed()来结束MIDlet,那么在调用destroyApp()时,最好传入false,代表这并非系统或硬件强制关闭,这时如果MIDlet不希望结束执行,那么它可以藉由丢出MIDletStateChangeException异常告知呼叫它的人:“我还不想被消灭,请待会再来。”

这里可以看出startApp()、pauseApp()及destroyApp()并非控制MIDlet生命周期的函数,它们只是一个提供初始化资源、释放资源的地方而已。

根据MIDP 规格书中所说,即使MIDlet处于停止状态,它仍然可以处理异步事件(Asynchronous Event),比方说Timer的事件或是其它回呼函数(Callback)。这将涉及到resumeRequest()的使用。resumeRequest()会将MIDlet从停止状态回到运作状态,并调用startApp()。由于当时MIDlet处于停止状态,所以必须依靠异步事件使MIDlet重新回到运作状态。

在一些范例程序中,我们常常只呼叫notifyDestroyed(),而没有呼叫destroyApp(),这是因为范例通常没有释放资源的需求,所以可以不用呼叫。但是如果是正规的程序,建议记得呼叫destroyApp(false)会比较好。

总结


通过本文的讨论,相信大家都可以发现MIDP更成熟了,功能更强了,但是也更复杂了。

附注:本文中出现的Java程序代码已在Java 2 SDK 1.4.x与J2ME Wireless Toolkit 2.0的Win32版本上完成测试。本文所有操作皆在Windows 2000 Professional与Windows XP Professional中文版操作系统上经过测试。本文的范例程序代码请至Http://www.javatwo.net/experts/moli/publish/下载。

名词解释

MIDP: Java API中面向移动终端的集合。通过与J2ME中的面向移动终端产品配置CLDC配合使用,就能够提供J2ME应用程序所需的运行环境。主要用于手机、PDA及双向寻呼机等低价位移动信息终端。

MIDlet: 即一个可以执行的J2ME/MIDP应用程序基本单位。除了继承自javax.microedition.midlet.MIDlet之外,还包括让此类别可以顺利执行的所有其它类别和资源档(只要是非类别档都称作资源档)所构成的集合,所以一般又称做MIDlet应用程序(MIDlet Application)。

MIDlet Suite: 许多MIDlet所构成的集合一般又叫做MIDlet应用程序套件。MIDlet Suite和MIDlet的关系,就好像Office与Word、Excel、PowerPoint、Access的关系。

JAR档(.jar档): 实际上包含MIDlet Suite的档案,属于ZIP档格式。

描述档(.jad档): 用来描述一个MIDlet Suite基本数据,以及该MIDlet Suite内含的MIDlet内含的MIDlet相关信息(类别名称、图标、程序名)的外部档案(不在JAR档内部)。

应用程序管理员(Java Application Manager): 负责将MIDlet Suite安装到机器上执行,以及负责管理MIDlet生命周期的机制(或软件)总称。应用程序管理员会根据使用者的需求安装、启动、停止或移除相对应的MIDlet。

- 作者: GeorgeKong 2005年12月16日, 星期五 12:09  回复(0) |  引用(0) 加入博采

诺基亚S40的手机都有哪些?MIDP版本分别是什么?
NOKIA S40的手机都有哪些?MIDP版本分别是什么?

这是我们在官方网站上找到的数据,可谓最为准确的。
我们分别以MIDP的版本分类,希望大家在下载游戏的时候能用得上这些资料。
其中有一些手机可能在中国大陆区并未销售,也列在上面了。
检查一下,你的手机是不是S40的?MIDP是哪个版本?现在知道该下载什么游戏了吧?

MIDP的定义:
http://www.chinamg.net/html/7/2005_11/article_286_1.shtml

MIDP 1.0:
7210、6610、3530、3510i、6650、8910i、7250、6800、5100、6100、6800 Americas、6200、3585i、3595、3300、6220、3300 Americas、6585、3586i、7250i、3586、6108、3100、6225、3200、3105、7600、7200、6820、6810、6010、3108、5140、6015i、6015、6012、3205、3120、6610i、3587i、3587、3125、2650、6651、

MIDP 2.0:
6255、3220、6170、7270、7260、6020、6235i、6235、6822、6102、6101、6230i、6030、6021、6155i、6155、6152、3155i、3155、3152、8801、8800、6060、5140i、5140、6230

还有一个特征:
所有S40手机的屏幕都是128×128像素

- 作者: GeorgeKong 2005年12月16日, 星期五 11:45  回复(5) |  引用(0) 加入博采

什么是MIDP?
什么是MIDP?

  MIDP:
  移动信息设备描述(Mobile Information Device Profile,MIDP)是一套Java应用编程接口(Application Programmer's Interfaces(APIs))。它们与有限连接设备配置(Connected Limited Device Configuration,CLDC)一起向诸如蜂窝电话等移动信息设备提供了一个完整的Java应用运行环境。MIDP中含有下列API包:javax.microedition.lcdui--用户界面(UI)API,它为MIDP应用提供了一整套实现用户界面的功能特性;javax.microediton.rms--移动信息设备描述提供了一种让MIDlets永久储存并在以后可以取回数据的机制。javax.microedition.midlet--这个MIDlet包明确定义了MIDP应用,也定义了和应用环境之间的交互。javax.microedition.io--移动信息设备还描述包括基于有限连接设备配置GenericConnection框架的网络支持。

  MIDP是向下兼容的,即MIDP2.0的手机能玩MIDP1.0的游戏。

  MIDP1.0有容量限制,软件不能超过64K。

  如果你的MIDP2.0手机不能玩MIDP1.0的游戏,那只能说明厂商没有严格按照MIDP标准开发游戏和硬件。

- 作者: GeorgeKong 2005年12月16日, 星期五 11:43  回复(0) |  引用(0) 加入博采

MIDP 2.0 增加的函數

MIDP 2.0 增加的函數

增加的包:

javax.microedition.media

javax.microedition.media.control

javax.microedition.lcdui.game

javax.microedition.pki

 

 

类名称

增加的函数

1

Canvas

public void setFullScreenMode(boolean mode)

protected void sizeChanged(int w, int h)

2

Command

public Command(String shortLabel, String longLabel,

               int commandType, int priority)

public String getLongLabel()

3

Displayable

public String getTitle()

public void setTitle(String s)

public Ticker getTicker()

public void setTicker(Ticker ticker)

public int getWidth()

public int getHeight()

protected void sizeChanged(int w, int h)

4

Font

public static final int FONT_STATIC_TEXT

public static final int FONT_INPUT_TEXT

public static Font getFont(int fontSpecifier)

5

Form

public void deleteAll()

public int getWidth()

public int getHeight()

6

Graphics

public void drawRegion(Image src, int x_src, int y_src,

                       int width, int height, int transform,

                       int x_dest, int y_dest, int anchor)

public void copyArea(int x_src, int y_src, int width, int height,

                     int x_dest, int y_dest, int anchor)

public void fillTriangle(int x1, int y1, int x2, int y2,

                         int x3, int y3)

public void drawRGB(int[] rgbData, int offset, int scanlength,

                    int x, int y, int width, int height,

                    boolean processAlpha)

public int getDisplayColor(int color)

7

Image

public static Image createImage(Image image, int x, int y,

                    int width, int height, int transform)

public static Image createImage(InputStream stream)

                         throws IOException

public static Image createRGBImage(int[] rgb, int width,

                   int height, boolean processAlpha)

public void getRGB(int[] rgbData, int offset, int scanlength,

                   int x, int y, int width, int height)

8

Layer

All

9

MIDlet

public final boolean platformRequest(String URL)

                   throws ConnectionNotFoundException

public final int checkPermission(String permission)

 

- 作者: kia126 2005年12月16日, 星期五 11:28  回复(0) |  引用(0) 加入博采