Archive for » 2008 «

浅析java字符编码(引子)

最近的项目由于要和多方欧洲ISV集成,进行数据报文的接收和发送,对于java字符编码以及处理方式略有一些心得,遂记之。

这篇引子先用一些直观的代码说话,给出一些直观的结果。

1. 写文件

如果要写一个简单的文件,就会有以下的代码:

BufferedWriter bw = new BufferedWriter(new OutputStreamWriter( 
                            new FileOutputStream(fileName), charset)); 
bw.write("中文123"); 
bw.flush(); 
bw.close();

其中charset主要有几类:ISO-8859-1(ASCII),UTF-8(Unicode),UTF-16(Unicode),GB-18030(ANSI local),GB2312(ANSI local)等等。

PS1: 如果OutputStreamWriter换成无charset构造方法,则charset默认为JVM的编码集。

本地的JVM编码集可通过System.getProperty("file.encoding")得知。我公司的台式机是GB18030(环境是xp英文,改了默认语言),而家里的笔试本是GBK(环境是xp中文)。所以这个值是由多方配置一起决定的,比如JVM setting,OS,OS setting等。

如果你的机器是ISO-8859-1,那么写入中文应该是会乱码的。

PS2: GB18030从字符集上来看基本是与Unicode一一对应的,但是从写入文件系统的种类和用途来分,它更多是用作本地ANSI。

PS3: 这里的中文字符串直接写到了程序中,并不是一种优雅的方法,通常的I18N做法是把涉及到国际化的文字写到资源文件里。

这个写文件的过程首先构造了一个JVM编码集的字符串,然后将它以某种charset转换,最后以byte[]并写到文件系统中。

2. 读文件

java i/o库提供两种读的方式,基于byte和char。而String也就是char[],所以java i/o提供的类似readLine()这样的方法实际上做了一个从byte到char的转换。

2.1 以byte方式读文件

int length = 0;
InputStream ins = new FileInputStream(fileName);
while (ins.read() != -1) {
    length++;
}
System.out.println(length);

注:此处虽然用ins.available()也可以得出同样的结果(因为文本很小,基本可以认为ins.available()就是inputstream的字节大小)。而实际上这个方法只是返回在无阻塞情况下当前所能读的长度,譬如大于8k的文件它也只会返回8192。

         
             length(byte)

charset

123

total

UTF-8

3

3

3

9

UTF-16

2

2

6

10+2

GB18030

2

2

3

7

default(JVM charset)

2

2

3

7

 

以byte方式读文件并不涉及解码过程,故这个结果是文件中字符串的真实存储长度。

其中UTF-8对中文字符以3byte编码,而对ASCII前128个字符优化处理,以1byte表示。UTF-16标准就是通常我们说的Unicode,对每个字符都采用2byte编码。GB18030是本地ANSI编码,中文字符占2byte,ASCII占1byte。default因机器而异。

PS: 你可能注意到这里有个10+2,+2的问题与Big Endian和Little Endian(字节序)有关,我们等到以后再说:D

2.2 以char方式读文件

BufferedReader br = new BufferedReader(new InputStreamReader( 
                    new FileInputStream(fileName), charset)); 
char[] buffer = new char[1024]; 
int readNum = 0; 
StringBuffer sb = new StringBuffer(); 
while ((readNum = br.read(buffer)) != -1) 
    sb.append(buffer, 0, readNum); 
String s = sb.toString();
 
System.out.println(s.length()); 
System.out.println(s.getBytes().length); 
System.out.println(s.getBytes(charset).length);

其实读文件的本质还是以byte流读,只不过byte到char用了一个InputStreamReader这么一个Adapter,并指定了解码方式。需要注意的是InputStreamReader的这个charset指定的是从文件读取byte[]的解码方式,也就是说它只是保证以byte流的方式把文件内容正确读出来,而之后读出的byte[]转换到char[](String)的过程依旧是通过JVM charset转换的。所以这段代码的输出结果就是:s.length()输出char[]的长度为5;s.getBytes().length输出JVM charset decoded byte[]的长度为7(因为我本机是GB18030);而s.getBytes(charset).length则输出JVM_charset decoded byte[] –> charset decoded byte[]的长度。当然这些结果都是基于正确解码的基础,否则会抛sun.io.MalformedInputException或者解出乱码(例如以utf8编码,又以GB18030解码)。

Category: java  Leave a Comment

Was 6.1.0.19的一个bug

现在的项目服务器环境是我配的,Was和Db2都update到了最新的fixpack。Was更新到了今年9月份的一个版本,就是这个6.1.0.19了。可是最近项目在服务器上测试经常down,运行一段时间就基本卡死,不过本机确没有这个问题。

最后怀疑是Was版本问题,于是本地Was也pack到了6.1.0.19。debug一下,发现很奇怪的异常:基本上每一次数据库查询就会出现以下错误:

[08-11-20 9:26:01:484 CST] 00000025 SystemErr     R Exception in thread “WebContainer : 1″ java.lang.RuntimeException: java.lang.NullPointerException
[08-11-20 9:26:01:484 CST] 00000025 SystemErr     R     at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:793)
[08-11-20 9:26:01:484 CST] 00000025 SystemErr     R     at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:873)
[08-11-20 9:26:01:484 CST] 00000025 SystemErr     R     at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1473)
[08-11-20 9:26:01:484 CST] 00000025 SystemErr     R Caused by: java.lang.NullPointerException
    at com.ibm.io.async.AsyncFuture.completed(AsyncFuture.java:111)
    at com.ibm.io.async.ResultHandler.complete(ResultHandler.java:195)
    at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:743)
    at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:873)
    at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1473)

[08-11-20 9:26:01:484 CST] 00000025 SystemErr     R     at com.ibm.io.async.AsyncFuture.completed(AsyncFuture.java:111)
[08-11-20 9:26:01:484 CST] 00000025 SystemErr     R     at com.ibm.io.async.ResultHandler.complete(ResultHandler.java:195)
[08-11-20 9:26:01:484 CST] 00000025 SystemErr     R     at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:743)
[08-11-20 9:26:01:484 CST] 00000025 SystemErr     R     … 2 more

之后的查询这个WebContainer的number就会++,这不down就奇怪了。

不过从异常信息来看,应该和代码逻辑没有太大关系,最后google到了这是Was 6.1.0.19的一个Bug,temp的fix方案是这样,打开Was控制台,在Application servers > server1 > Web container > Custom Properties里new以下的属性:

Name : com.ibm.ws.webcontainer.channelwritetype
Value : sync

重新启动Was即可。

Category: java  Leave a Comment

几本值得关注的eclipse书籍

以下几本都是eclipse的经典书籍,均尚未出版.

Eclipse: Building Commercial-Quality Plug-ins, Third Edition
EMF: Eclipse Modeling Framework, Second Edition
Eclipse Modeling Project: A Domain-Specific Language Toolkit

其中第三本应该是GMF的第一本权威书籍,zx的blog中还提到过.

Category: java  Leave a Comment

搜狗五笔

从上周开始,由于固话号被撤,一直上不了网,周末这两天顿时觉得很无聊…于是周六晚上跑到老刘家蹭网蹭饭.

无意间老刘说搜狗好像出了款五笔输入法,于是上官网看了眼,基于五笔86,好像非常不错.自从用电脑以来,输入法一直忠于最原始的五笔86输入法,其他的基于此的诸如万能,陈桥,个人感觉用户体验都不是很好.而今天试用的搜狗五笔,非常非常爽,以致于使用之后有种"我找你找了好久"的感觉.

以下是一些我的个人配置,可能跟我一样用了十几年的原版五笔的用户也会做这些配置.

调频:

image

中文默认的标点使用半角:

image

还有就是搜狗五笔的词库比原版大了很多,这样诸如"奭"这种原版词库没有的字能轻松地打出来.但同时却有些"幸福的烦恼":由于词组比原来扩充了很多,这样一些原版是唯一的字或词组却有多个选项,这些不必要的选择就是annoying的事情了.

例如输入rtfp,你只是想直接输出"挺"字.可以却出现如下的画面导致你还要多做一次选择:image
sogou允许删除自定义的词组,但我觉得非自定义的词组也应该能被删除.

另外,还有一些诸如与个人帐户同步词库等功能.总之,就是很好很强大了.

Anything is contribution

事隔三年,再次接触eclipse plugin开发,免不了有很多的感触,so log it.

  • contribution
    想必看过<contribution to eclipse>这本书的人都不会对这个词陌生.contribution也是eclipse开发的一种普遍的开发思想.
    例如你想在别人开发的插件上加上自己的东西怎么办?首先要扩展一个eclipse或是其他插件定义的扩展点,然后作objectContribution或者viewContribution.前者指某个对象被选中时,你所扩展的动作被触发.viewContribution指的在activited的view上做扩展,小三角的下拉菜单,和view并排的toolbar等等.
    image 
    如果你想覆写这个插件的某个部分,那么只作object或view的contribution是实现不了的.这需要将需要覆写的这个部分抽出一个扩展点,然后相应的实现这个扩展点.
    contribution是一个非常重要的概念,因为无论你是在别人的插件做扩展还是自己从头写一个插件,都是一步步的迭代,一步步的扩展,最后你写完的N个小插件完成一个整体功能.如果你最后写出来的插件只是一个jar,我觉得并不能算是一个合格的contribution,起码有点bad smell,因为你自己都没在自己的插件做扩展,那么别人更不可能在你的插件上做扩展了.
    eclipse3.4将以前一个单独发展的插件eclipse spy打包进了pde的runtime,所以你可以直接在3.4中点击Alt+Shift+F1查看激活窗口的plugin信息.
  • model, EMF与MDA
    model在软件开发中的作用不言而喻.数据库设计中有这么一句话:数据存在的时间比利用这些数据开发出来的系统要长得多.而model比数据更进了一层,有点抽象到底的味道.
    现在公司做的这个项目有web和plugin两部分,其实两部分用的模型是基本一致的.在web上以数据库的形式展现,而在plugin中以EMF的方式展现.而开发方式都是model driven的.web中以model生成结合相应的ORM框架生成DAO基础代码,而在plugin中生成核心的model代码,model.edit代码.
    EMF确实是一个精心设计的框架,生成的代码质量很高,比如它的edit代码,提供了相应的模型元素的provider,当然你得在你的代码里做一些转换才能利用.
  • lightning的记忆
    lightning是三年前做的一个plugin,曾经靠这个项目拿了很多奖.更重要的是在这个项目中,熟识了一批对我影响很大的朋友.比起浮云般的奖项,这才是最为珍贵的.
    现在回过头来看,lightning很多地方需要改进.
    首先就是版本问题,lightning至今仍只能跑在eclipse3.0上,这一点是比较致命的.从开源软件的角度来说,尾数是偶数的版本都是比较stable的.eclipse也不例外3.0,3.2,3.4都是非常稳定的版本,比起上一个版本也有很多的新特性.所以lightning如果要做扩展,就非常困难.比如用CNF针对模型做一个viewer tree,那么不在3.2以上的版本就无从谈起.
    其次是SWT/JFace中的一些best practice,这部分当时的布局是用的GridLayout.但是从今天我所实践的来看,FormLayout应该是最提倡使用的,而实际上也确实如此.FormLayout基本上是万能的,能很好的设计各种布局需求.如果继承的父类定义了**layout,那么子类最基础构造的composite必须用**layoutdata,这点是必须遵守的.比如一个dialog继承了TitleAreaDialog,那么这个dialog最外围的composite需要setLayoutData(new GridData(GridData.FILL_BOTH)).
    而对于父与子关系的composite,也是这个道理,父类设定的**layout,子类必须设定相应的**layoutdata才能生效.
    最后就是模型和性能上的改进.当时FLASH的模型全是自己设计,持久化的.主要是用java2D画基本的图形,然后定义转换算法,做出变化的过程.其实当时做到一半的时候,听说了GEF和EMF,但考虑到当时的资料很少,而且java2D已经研究有了一定经验,最后还是放弃了GEF和EMF.而从今天来看,这两者可以很好的配合,并解决lightning的需求,而且java2D是基本AWT的,相应的图形放在eclipse基于SWT的view上,必须用SWT_AWT这样的转换操作,而这在一定程度是有性能问题的.

Category: java  Leave a Comment

Olympic Football Final

昨天终于在奥运即将结束的时候,有幸去目睹了一下鸟巢的风采.票是梓特同学的GF弄的,RMB 800,我和涛哥抱着"今生能看几回奥运"的心理,欣然前往.

票是足球决赛,阿根廷对尼日利亚,中午12点.这个时间真是很尴尬,但是我发现2000年和2004的足球决赛都是艳阳高照下进行的,不知道是为什么.

早上九点多出门,13号线,10号线,8号线,凭着当日门票坐城铁或公交都是免费的.比较假的是在10号线转8号线的时候偶遇杜伊.

final1 

更比较假的是旁边一个哥们从后面赶上来,直接把他价值不菲的单反塞给我们,让帮拍张,然后头也不回的去追杜伊了.orz…就不怕我们直接掉头走了么,哈哈.

终于来到了传说中的鸟巢,座位是3层的20排,好远啊.看不清球员的脸,不过能第一次从全景欣赏一场足球决赛,也是相当激动的了.
开场后场面略显沉闷,梅西和里克尔梅还是阿根廷最有威胁的球员,第一次欣赏里克尔梅从容的背身拿球,摆脱,组织进攻,大师级的优雅一览无遗.梅西个人能力摆在那儿呢,无论是右边路的突破还是中路和队友踢墙二过一,都能激发起观众的呐喊.没办法,作为一场奥运会的决赛,就是看球星来的.不过梅西和队友的配合还算不是默契,几次二过一都差那么一点儿.

final2

进球终于来到了,58′,Di Maria,这位在半决赛对巴西就表现得很抢眼的左前卫接梅西的直塞,一脚精彩的吊射打破了僵局.

DiMaria
DSC02980

进球之后双后都还有不少机会,但是阿根廷表现的更像是一支国家队,战术素养,大局观和对场面节奏的控制.尤其是马斯切拉诺这道铁闸,没有给尼日利亚太多机会.最后,阿根廷如愿卫冕,比分也和四年前一样,只是进球者从特维斯换成了迪马利亚.

DSC02981 

颁奖仪式,巴西的众多大牌也到场了.

collage 

最后,给个五星红旗的特写.

DSC02989

Category: dailylife  2 Comments

MOTD归来

就当奥运如火如荼地进行之时,新赛季的英超联赛上周末已经鸣金开战.so,每周末又可以下载高清的BBC Match of the Day(简称MOTD)欣赏了.

昨天晚上看了Day1,第N次感叹英超已经全方位将其他联赛甩在身后.随便聊聊看完的感受吧:

保罗因斯入主布莱克本,感觉执教能力和经验还差马克休斯一筹,本特利出走白鹿巷,实力整体有所减弱,不过圣克鲁兹还是可以依赖的.加上Paul Ince,曾经在MU效力过的英超现役主帅已经有4名了,还有Mark Hughes, Roy Keane和Steve Bruce(拜托布鲁斯同学不要再将名字缩写印在教练外套上了).

富勒姆首轮就输给了升班马,他们本赛季还是为保级而战,不知道本赛季是否还有上赛季最后一轮挤掉雷丁的运气.

阿森纳本赛季中场人员流失严重,而纳斯里的到来从任何方面来说,都是非常正确的选择.假以时日,"皮雷二世"将横空出世.

罗比基恩以2000万英镑的身代来到安菲尔德,我觉得这么高的价格有待商榷,尽管高佬已经出走朴茨茅斯.从第一轮的表现来看,小基恩表现得很积极,甚至有点过了头,将托雷斯一个空门补射给挡出…非常尴尬.托雷斯还是红军最可以依赖的,他已经不再是马竞那个hell boy了.

再来说说热刺吧.热刺一直是我非常欣赏的球队,老板非常有进取心,从这几年的经营,买人就可以看出,他们不甘居于第二阵营,不过打破传统四强的垄断,还是有很长的路要走.今年从阵容上补充了相当一部分有实力的球员,莫德里奇,本特利,多斯桑托斯.不过对热刺最伤的就是小基恩和贝巴托夫(虽然还未正式离开)的出走,而达伦本特不能被寄予过多期待.

最后来看看贝赫拉米.是的,这位前拉齐奥的右中场已经转会铁锤帮.我并不是说贝赫拉米有多强,但这种其他联赛准强队的绝对主力流失到英超的现象,却是耐人寻味的.而这种例子其实有很多了,上赛季乌迪内斯的蒙塔里就跳到了朴茨茅斯.这种信号已经很明显了,就看其他联赛能不能忘记历史,重新迎头赶上了.

伪问题 or not

来公司之后接到的第一个任务是把原来的一个数据库重构,中间遇到两个小问题.算不算问题?这是一个问题.

第一个问题可以抽象成这样:
表p(erson)和表a(ddress),他们原来都没有主键,表p的属性有p_name,表a也有p_name,是直接引用表p的p_name,然后还有些type,phone之类的.
现在要做的事情就是把两表都加上id主键,然后把表a的p_name改名为p_id,并通过其以外键的形式和表p关联起来.虽然我不知道出于什么原因这些表设计之初没有主键,无所谓是否把它看成一个伪问题,反正只是一条update语句搞定的事情.alter之后的表看起来像这样:

表person  
p_id p_name


表address      
a_id p_id(p_name renamed) type phone

注意现在address的p_id是原来的p_name改名改过来的,数据还是person的p_name值.
我首先想到的是update person, address set address.p_id = person.p_id where address.p_id = person.p_name.
悲剧,update操作后只能接一个表.所以想当然的把select中的思维拿来过做update是不行的.
再次试验,update address set p_id = (select p.p_id from person p, address a where a.p_id = p.p_name).
再次悲剧,提示update操作set的值必须是唯一的.
括号里的子查询结果确实是得到了正确的结果集,不过这样赋给p_id是不允许的.
最后的语句是这样的:
update address a set a.p_id = (select p.p_id from person p where a.p_id = p.p_name fetch first 1 row only).
特别注意这里有个first 1 row only是db2的方言,相应数据库应该换成取头一条记录的相应语句.

第二个问题就是在原来的表上更新id字段,因为以varchar作主键无法自动增长,所以先设成default为0.
这个问题你当然可以说改成integer或者bigint就完全不存在这个问题,不过牢骚归牢骚,问题还是得解决.
首先想到的是能不能用一条语句就搞定了.尝试了一下,也搜了一些db2的函数,不是那么容易,要做+1操作还得做转成数字的操作.一条语句应该是不行,或许写个存储过程能搞定.
然后想到的就是用N条update语句做了,因为update每次只能set一个value.手写N条语句是不可能了,最后实现的方法是用JDBC先把所有id为0的取出来,然后遍历,同时构造相应的domain对象,将其加入一个list.然后把数据库的id为0的纪录清空,遍历list,将每个domain对象插入.其实最后用的是insert操作而不是update,update的话还是有很多限制.
虽然这个方法看起来比较诡异,anyway,还是解决了需求.

最后来看看这两个问题,虽然你有一万个理由置疑这个问题为什么会出现,并牢骚满腹地抱怨为什么会有这种伪问题.但是,一再坚称伪问题也只能说明你不敢面对.只有当你如庖丁解牛地分析各种伪问题,并给出solution,才说明水平到了新的层次.

北京一周流水帐

9号考完应该是大学期间的最后一门考试,第二天就马不停蹄地奔赴北京.到今天已经一周了,一年之后再次来到北京,感觉还是有很多不同的.

交通更挤了
首先是北京站地铁不停车,于是只能拖着大包小包过天桥坐公交车,坐一站到崇文门坐地铁,再去目的地.
来北京一直是在回龙观的同学这住,怎奈回龙观门口也出现了以前西直门才有的情景.据说龙泽的长龙阵更加壮观…
公交车倒和以前差不太多,昨天和梓特上车差点被挤下去,不过以前在东北旺也有类似的经历.

房子好难找
由于是在得实上班,所以一直都在找西二旗附近的房子.来北京之前,一直都和锦波联系,他在北京找,不过一直都不理想,而且都是中介,得收一个月房租的中介费.最后我还是暂时住在回龙观涛哥这.
来北京后,同学和同事都提醒我最好不要找中介的房子,所以一直在网上找个人的.无奈西二旗附件房源太少,而且条件并不好,一般都是合租.昨天去看了一家智学苑的,我去看的时候已经有人和房主在谈了,我觉得性价比很低.
离公司近,价格合理,非中介,房子干净,经过这几条筛选的房子基本是没有了.那么去掉离公司近这条,我现在住的回龙观这块已经是很好了,而且都是挺好的同学,加上今天询问到的CDL不给外地实习生房补这条消息,让我渐渐没了找房子的动力.

同学更多了
以前找工作一直在北京和上海之间徘徊,我更倾向于北京,因为有很多同学在身边,这样的感觉很好,会让你聚在一起的时候非常放松.不过想聚一次实在不易,前天和cowoo,solit,lookou,小花,锦波在清华南门附近小聚了一下.聚首过程相当困难,问路,接人,打车,最后终于是顺利会师.我这个自认为非常路痴的人居然是最先到的,汗一个.
北京实在太大了,也使同学的联络有了很多障碍.如果以后都住在差不多的地方,还是不错的.那天我从龙跃二去和谐家园,就比较近,在老刘家蹭顿饭,非常不错,然后去陪老陈买电脑,呵呵.

IBM好像也并不清闲
这是上班第一天的感觉,起码我这个组貌似是这样的.第一天下午就给了我五个文档,全是英文,看得脑袋直疼.今天就好得多,有思想准备,带了两本书过去调节下.下午装了个WID,全称叫Websphere Integration Developer,包括了RAD,但更多是作为一个SOA整合的工具存在.装一遍自己定制选了ESB的一些附带环境,结果很尴尬,没装成功…卸了重装完已经快下班了,大概用了下,居然用的是eclipse3.0的壳,有些地方不是太习惯了,像不能一键折叠全部方法代码块,也没有单个变量在类中的高量显示.感觉回到了大二用3.0的时候…
今天临走的时候给了我一堆代码,明天就开始看代码.不出预料的话,这周就要coding了.

Category: dailylife  6 Comments

轮回之面试篇(续)

前天经过一番波折,我总算收到了IBM CDL的正式实习offer,为找工作开了一个好头。当然革命尚未成功,想留在IBM还需努力。

首先总结一下上次面试提到的几个面试结果。
1. Intel上海
这个忽略。
2. IBM CDL北京
这是个测试的职位,一周后并没有给我消息。我感觉应该是没戏了。于是托吴老师帮忙问了一下情况,得到的回答是那边不想进人,于是我这种想留下工作或者否则就得在实习期间找工作的,就不是太想要。虽然测试职位我并不太感兴趣,但当时如果他们决定要我,我应该还是会答应。
3. 博奥杰上海
面试完到现在,BO上海那边还没有任何回信,也就是说没有任何人的任何面试结果回复。加上面试问的都是非技术问题,看样子只是来学院走个形式,没有招人的意思。而且在面试的时候,我跟面试官聊,他说其实公司更希望实习生做测试方面的工作。我不知道这是不是只是BO的风格,或是上海公司的风格。难道他们开发不从校园招聘招人吗,都是社招?
4. 百度北京
这个非常遗憾,一面就挂掉了。其实在写上一篇BLOG的时候我就已经知道这个结果了。关于百度面试挂掉的原因,我会专门写一篇分析一下。或许我以后没有机会去百度了,但是这次失败的教训,是一定要拿出来思考的。或许对于我来说,意义并不大,因为我不大可能完全转向另一个方向。但是对于我的师弟们,会有比较大的借鉴意义。

再来说说得到现在这个offer的过程吧。参加的是IBM一年一度的蓝色之路实习生招聘,先在网上投简历,选择几个职位。我把5个都选满了,3个是蓝色之路的,2个是青出于蓝的。
1. 笔试
笔试就是著名的IPAT考试了,分为矩阵题,数列题,应用题三部分。这个本科也参加过,不过这次不同的是还有一个小时的技术类面试,都是选择题:Java和C++二选一,再加上一些设计模式,数据结构,正则表达式这些非具体语言的题,有单选的也是多选的。
由于本科做过IPAT的题,这次我只是考试当天上午搜了一下,下午考的时候发现矩阵题还是很难,15道题空了4道(后来才知道这部分是答错了不扣分的。。。),数列和应用题各空了一道。总的来说,对于IPAT经过一定的训练肯定会答的很好。当然我所说的训练不是机械的做题,而是找出最快的方法解一种类型的题。例如矩阵题,有一种类型是叫你从某一列从上往下数,某一列从下往上数,以此类推,然后让你找出最先出现五次的字母。如果你只是按照题目意思来做的话,那就太浪费时间了。把题目反着读,反向找,五个字母有四个字母出现至少一次,那么剩下的就是题目要找的答案。当然IPAT的题库很大,你肯定不能把所有的类型都准备好,即兴发挥就好了。
而后面一小时的技术题跟一般的笔试题差不太多了,语言题部分(我当然选了Java)会问你一些比较深的问题,比如垃圾回收执行的时机等,而比较难的是多项选择,因为有错误答案就没分。这部分每道题答题卡上都有分值,像设计模式这类一般是3分,而像比较基础的是1分。所以检查的时候着重看看分值高的吧。
2. 面试
这次IBM的面试给我的感觉是非常高效,5月28,29,30号,三天三个电话,30号manager面我的时候就给了口头offer。只不过从5月30号的口头offer等到6月20号的正式offer,又经历了“好事多磨”这个阶段。
28号的面试可以称为0面吧,一个MM打来的电话,问了一些项目的经验,并没有想象中的英文自多介绍,英文回答等等。我不知道这个MM是不是HR,因为后来的电话都是她先打过来的。这次面试面了20分钟左右。最后MM说过两天会有一个她的同事再跟我谈谈。
29号的面试是那天下午打过来的,刚好那天在A楼自习。那天的面试经历我自己的评价是“非常糟糕”。打过来的时候毫无准备,只能在A楼靠边的窗户那接,基本要捂住一只耳朵才能听清楚对方在说什么,并不能很好的发挥。面试官似乎对J2EE规范非常看重,首先问我一个项目中用到了websphere的什么功能。我说其实开发的时候分为两部分开发,一部分只用到了普通web服务器的功能,开发时用tomcat部署,另一部分由于用到websphere MQ,所以这部分开发时候就用的websphere中EJB容器的功能,最后集成的时候把web和EJB打成一个EAR包最终在websphere上部署。然后问我整个项目的事务框架是怎么样的。我说用的spring的,然后再追问MQ那边应该是用的webphsere自己的事务框架吧,我说是。继续追问那这二者结合的时候事务这部分会不会有冲突。说实话我基本没考虑过这些,关于事务框架只是SL的时候看过一点,而烟草局这个项目由于有些冲突我直接把spring的事务配置文件删了。。。
这个问题过后,由于项目中采用了Hibernate3.2,面试官就问了我JPA的一些东西。说实话,对于Hibernate的annotation我确实曾经研究地比较深入,用的也比较熟练。但是他问我的问题都是专注于J2EE规范。他问我在项目中是使用的API是什么的。其实我对这块的概念也比较混淆,一开始我回答是Hibernate的JPA。但面试官解释道,在Hibernate3.2后,已经兼容标准JPA,所以再追问我。这回就有点迷惑了,回答得支支吾吾的,一连用了几个“好像”。其实答完这个问题,心里就比较郁闷了,感觉答得很差。后来也不知道哪根筋错了,把websphere的版本说成了6.5,其实是6.1,好在我说了是支持jdk1.5的那个版本,不然面试官还不知道怎么看我。。。最后让我谈了谈Hibernate的缓存机制。我说了说我在项目中使用ehcache的过程。面试官又让我说说一级缓存和二级缓存的区别。这个问题答得也不好,Hibernate的这些细节比较久没看了,于是说一级缓存好像是在session重新load一个相同id的对象时,会从缓存中取,二级缓存就说得不知所以然了。后来回寝翻了翻书,其实一级缓存是在session范围内,而我所答的其实是内部实现的细节,二级缓存是在sessionfactory范围内。当时面试官给我解释了一下二者的区别,说的是一者是session,一者是application。其实这个解释是有误的,hibernate的session并非httprequest中的session。
总的面试过程就差不多是这些,感觉答的很废,很多支支吾吾的,发挥的很差。当面试官问我有没有其他问题时,我也没有问接下来会不会有面试了。因为我已经自己给自己判了死刑,觉得肯定不会再有机会。
我至今还记得面试完那天的沮丧心情,因为是我自己让这次机会擦肩。因为从一直的学习方向上来说,我并不能给自己什么借口拿不下这个offer。我不需要花太多时间就能将这次面试准备得再充分一点,可是我终究没有做到。晚上我打电话给cowoo聊了将近20分钟,cowoo鼓励我说结果没出来,还不一定呢。我只是自嘲地笑笑,因为我知道机会已经溜走了。
3. 口头offer
天无绝人之路也好,峰回路转也罢。5月30号上午,我又接到那位MM熟悉的电话,说manager1个小时会跟我聊聊。我自嘲地说,我本以为没有这次机会了,昨天的发挥很糟糕。MM很nice的说:“不会啊,我和我的同事都觉得你很有潜力。”不管怎么说,我很幸运地拿到了终面的机会。面试过程首先是manager介绍了一下部门的情况,是主要做SOA的,但并不面对某个项目或者产品,而是把若干个项目或产品的共同服务抽取出来做一个通用的service,其实这也是SOA的核心思想。面试大概持续了不到20分钟,总的感觉很轻松,manager夹杂的英文单词也听得比较清楚,一些地名我也听懂了,像斯德哥尔摩,布里斯班。然后,manager向我confirm实习时间,得知我可以从7月份实习到明年5月份,说了一句:“太好了!。”最后,manager跟我说IBM见,然后让他的秘书向我交待了实习的事情。一会秘书给我来电话,说正式通知会在两周后发,让我注意查收邮件。
4. 正式通知
没想到从口头offer到正式通知还是经历了一定的波折,回想起自己今年的面试经历,都不是太顺。像百度,莫名其妙地没收到笔试通知,而那是刘斌给我推荐的,后来一面又隔了一个月才面试。而现在却是gmail邮箱收不到信,星期五下午我打电话过去,才通过一个163邮箱收到了正式通知。

近两个月的找实习终于画上了一个圆满的句点,在其中我看到了自己的很多很多不足。有些是我从大二开始技术学习就犯下的思维错误,有些则是我对找实习找工作很多东西的准备不充分。虽然我不喜欢这种以找工作为驱动的学习方式,但无可否认,在这个过程中,发现了许多平时学习中有意或无意回避的技术问题。这些都需要时间的积淀,在与自己的博奕中发现自己正身处何方,将去往何处。

再过一个月,我就将出现在曾经熟悉的北京,上地,软件园,东北旺,西二旗地铁站,362公交。。。

Category: dailylife  2 Comments