月度归档:2010年01月

LineNumberReader和FileWriter同时使用碰到的问题

今天上班有个任务就是将之前产品中的示范代码有一些不规范的地方进行修改,使得能在多平台顺利运行,主要是文件名大小写的问题。由于之前示范代码编写者在跨平台上编码经验相对不足,所以编写者在写代码的时候并没有严格的大小写意识(主要原因还是因为Windows不区分大小写,而代码的测试均是在Windows下进行的),造成很多遗留问题。产品中有示范代码64个,大小写问题几乎无处不在,还有一个就是跨平台产品支持的数据引擎与Windows不一致,之前的Windows版本中有不少的示范代码使用了Windows平台特定的引擎类型,也需要进行修改。

修改的方法可以有很多,最为简单和直接的方法,应该是一个个程序运行,一个个文件检查,逐个进行修改。我想作为程序员的我们,肯定是不愿意做这么无聊而重复的工作的。那么搞定这个无聊而重复的工作呢?首先分析一下已有的示范代码的特征,虽然之前的代码存在诸多不规范的地方,但是在一些方面还是存在很多共性的,大小写出现错误的肯定是在设置数据路径的时候出现的,设置引擎类型的代码更是固定的,之需要使用几个非常简单的正则表达式就可以将其完全正确替换了。所以我们选择了读写文件的方法来完成这个任务。

在实现这个功能的时候,使用到了LineNumberReader和FileWriter两个类,每读取一行,使用replaceAll(String regx,String str)方法对该行进行替换,之后再使用FileWriter将替换后的文本写入文件:

File file = new File(sourcePath);

try {
lineNumberReader = new LineNumberReader(new FileReader(file));
String line = lineNumberReader.readLine();
fileWriter = new FileWriter(file);
while (line != null) {
line = line.replaceAll("\\.xxx", ".XXX");
fileWriter.write(line+"\r\n");
line = lineNumberReader.readLine();
fileWriter.flush();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
lineNumberReader.close();
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}

执行的结果是,64个示范代码中,总会有几个会出现一些很奇怪的问题,那就是修改后的文件丢失了很多文本,导致编译不通过。那么问题在哪儿呢?经过多次分析和调试,最终发现当LineNumberReader和FileWriter指向同一个文件的时候会出现该问题,如果将源文件处理后的结果写入到一个新的文件中便不会存在这样的问题。那么究竟是哪里出了问题呢?来看一张图

在这张图中我们能看到一些信息,LineNumberReader对象中有一个cb字符数组,大小为8192=1024*8.

在我整个的调试过程中,我一直关注着最后一个字符,在整个过程中,这个位置的字符一直没有发生改变,而最终写入到文件中的最后一个字符就是该字符,这难道只是一个巧合吗?

现在让我们更换一下代码将原本使用同一个File对象的代码,改成使用另一个新文件对象的代码来重新调试一下。

先执行代码,查看结果发现,文本的内容完全被写入到新文件中,并没有出现丢失文本这样的情况,那么我们再来调试一下,我们再次来监视cb[8191]处的值,这次我们可以发现在LineNumberReader对象lineNumber==319的时候,该值发生改变。

====我是分割线======

综合上面的两种情况,我们可以得出一个结论,当LineNumberReader和FileWriter同时指向一个文件的时候,系统在写入文件的时候并不是逐行逐行写入,而是先记录下来逐行的内容,并且是记录到LineNumberReader的cb字符数组中。该数组的大小固定为内存最小单位8K,也就是大小为8192的数组,该数组将保存初次初始化FileWriter对象时读取的文件内容,在之后的每次FileWriter写入操作均是改变该数组中存储的字符值。这样导致的结果就是,如果当前的读取的文件较大,就会存在丢失内容的问题(最多保存8192个字符,含空格和换行)。而使用一个新的文件来进行修改后内容的写入就不存在这样的问题,当FileWriter需要使用到flush()方法来将当前缓冲区中的所有内容写入文件之后,LineNumberReader中的cb数组内容也将发生改变,指针下移,读取下一个块大小为8192的内容,直到文件末尾。

所以在使用LineNumberReader和FileWriter的时候需要注意这一点,如果实在不愿意多生成一堆新文件的话,可以在写入完成之后,将原始文件删除,而将新文件更名一下就好了。

SuperMap Objects 碎碎念

SuperMap Objects是SuperMap Software Co., Ltd. 成长的关键,最早公司创建之初公司便同时启动了两个项目,一个便是传统GIS中最为突出的桌面产品,另一个就是组件产品。

组件产品又作为桌面产品的基础,为桌面应用提供相应的功能。从SuperMap Deskpro 2000到现在的SuperMap Deskpro 6R,一直都是这么一个模式,SFC组件为SuperMap Deskpro系列产品保驾护航多年,不过近几年SFC组件逐渐进入后期维护阶段,SuperMap Deskpro也进入维护阶段,主要对功能的集成和细化进行深入挖掘,更多的是从软件可用性提升以及功能正确性,分析高效性上来提升Deskpro产品的市场认知度和用户体验。基于SFC(SuperMap Foundation Class)组件有一系列的产品,有为我们所熟知的SuperMap Deskpro、SuperMap IS .NET和eSuperMap,从桌面到服务器,再到嵌入式,甚至还有国土行业的一些深度行业应用等等。SFC已经为SuperMap带来了十年的收益,更是为SuperMap品牌提供了前期非常坚实的基础沉淀。那么为什么不继续深入SFC组件产品的研发,而是转而进入了一个后期维护阶段,目前的工作主要集中在后期缺陷的维护呢?主要原因有:

  1. SFC组件式基于COM技术的,称为SuperMap Objects COM,现在依然有很多的产品和项目的基础。但是COM技术毕竟不再是如今软件开发中的主流,存在着诸多的不足,作为平台厂商,固守一方市场固然有利可图,可是此计并非长久之计啊。为用户以及二次开发商创造价值才是平台厂商应该做的,如今的软件开发中(特别是项目实施中)Java/.NET无疑已经是十足的宠儿了,那么尝试转型已成必然之势。
  2. SuperMap Objects Java/.NET是基于UGC(Universual GIS Core)共相式GIS内核封装的组件产品,内核采用标准C++(此为号称,到底标准程度多高,各位看官且看且猜就行了),与平台相关性降至最低,依托Java/.NET快速而高效的二次开发能力,已经逐渐成为了用户和二次开发商首选的项目实施和开发组件。
  3. 服务器产品需求的激增,由于服务式软件SOA/SaaS等概念的逐渐成熟,催生了服务式GIS,GIS领域顿时服务器产品的需求指数上扬。国家基础地理数据中心,各大城市共享数据平台的建设,国家技术设施的信息化项目,都能看到服务器端产品的身影。服务器端产品对效率和跨平台的要求更高,而COM组件明显在跨平台和效率上不及UGC系列产品,由此SuperMap Objects Java/.NET走上了大舞台。
  4. 云计算概念的成长和应用,诸多厂商开始宣称自己站在了云端,依托云计算的优势能为他们的客户带来更多的价值,节约更多的成本。云计算中最为美妙的就是,任何硬件、软件、服务资源均不以实际形态暴露,而以统一的接口提供给用户,所有的资源均以组件式形态存在于服务端,客户端只需处理请求与响应。那么组件式GIS无疑是GIS云计算中非常重要的一个环节,插件式可定制化的服务,跨平台多地域服务的共享,无疑将为更多的用户带来更多的价值,而成本会更低。

SuperMap Objects Java/.NET

上图是SuperMap Objects Java/.NET产品的实现原理,至于细节,相信众位看官稍微了解一些关于封装机制的都一目了然了。功能性的代码完全由UGC完成,而接口的设计与实现完全由组件层来完成,组件层可以再更具自身语言平台的需求增加一些控件和相关产品的设计开发。例如.NET组件在C/S架构中应用广泛,用于对于桌面应用场景的需求较多,那么易用性高、定制性强、可设计的控件无疑会为客户带来更多的价值空间;而Java组件的优势应用在服务端,B/S架构的产品也不少,在服务端的表现可以交由iServer系列产品(基于SuperMap Objects Java开发的服务器产品),那么客户端呢?新近稍热一点的 JavaFX是Sun公司首推的RIA解决方案,也许用户的应用场景也会随着产品的升级而出现这一方面的需求。

其实组件产品分两大语言体系是一个比较科学的分类

  • .NET技术依托微软强大的技术后盾,在桌面应用上日益成熟早已是桌面明星了,SuperMap Deskpro .NET就是基于SuperMap Objects .NET使用Ribbon界面库开发的新一代GIS桌面GIS产品,从产品易用性和体验上作出了很大的提高,不过性能目前还存在一定的问题(组件产品的瓶颈问题导致)。
  • Java跨平台的特性无疑是最让人津津乐道的,类似于政府和大型服务企业均采用的Unix和类Unix(各种Linux发行版)系统和硬件,对跨平台的要求显而易见,SuperMap Objects Java基于标准C++,完全可以摆脱平台限制,在多平台上表现得游刃有余,填补市场上很大一块空白(其他厂商也有类似的产品和解决方案,但是均是采用中间件方式完成,效率和易用性上相对较差,对用户和二次开发商的开发成本要求过高)。
  • 两种语言技术体系产品,保持同一份设计同时开发测试,接口文档高度一致,二次开发用户选择开发平台的决策成本大大降低。无疑将会让更多的二次开发商,在低成本的情况下可以尝试更多项目的投标生产,为其带来更多的价值。
  • 两个产品由一个领导带领设计开发,更能突出其特点的一致性和延续性,降低用户和市场对该产品和品牌的认知成本,大大增强了组件产品的产品化和标准化。

================我是分割线==================

来到公司已经快半年了,对项目产品和架构上曾经都颇有微词,迄今依然有些怨言,以上就是我对目前SuperMap Objects Java/.NET系列产品的一些碎碎念,其中均是纯个人想法和行为,有一些猜想更多的是臆断。不过猜想也好臆断也罢,终究是我自己思考的一些沉淀,摆出来,凉一凉,晒一晒,淋雨发霉也好招来板砖也罢,纯属博主个人呓语,众看官且听且过是也。

开通SuperMap Objects专栏

首先声明,本人确实是SuperMap Software Co., Ltd. 的一名员工,目前就职于研发中心,从事软件开发的工作。

对于SuperMap Objects有着自己的理解和认识,有自己想说的一些话,不过说得对不对就不得而知了。对于职场上的一些常识和非常识,我一概不知,我会说我想说的,说我能说的,当然我不可能透露关于工作进度的只言片语,也不可能透露关于公司产品方向的任何信息。但是,我想我会猜的,反正我也听不到什么有价值的信息,那么为何不来一些自己的猜想呢?Yes, why not?

============我是分割线=============

该专栏主要针对SuperMap Objects的新特性和可公布的新消息作出广播,并偶尔来些剧透和爆料,也许会有不错的效果哦。我想作为一个GIS的从业人员,作为一个组件开发人员,报导关于自己产品的一种心态平衡非常重要。

首先组件是公司起家的法宝,其次是公司上层服务器产品的基石,是底层类库产品的延续,可所谓处于公司产品结构的腰部。我们都知道腰对于一个人的重要性,所谓无腰者不人也,就是这么一个意思啦。然而我们平日看美女的时候,先是头后是臀,腰经常是被略过的或者只是为了衬托臀的丰满而窈窕地存在的。那么作为一个腰,我们要如何做好这个产品呢?在做产品的过程中,如何勾起众位看官的欲望呢?也许腰风就在一夜起,顿时洛阳腰贵,作为腰子的我可能也会着实火一把哦。

所以该栏目的主要内容有以下:

  • SuperMap Objects 产品的最新小道消息(绝非官方消息)
  • SuperMap Objects 产品的开发技巧
  • SuperMap Objects 产品的八八和卦卦

众位看官,看过且看过,切勿传播,一旦小站被领导发现,可能便有关闭之忧。还望各位慎重慎重谨慎谨慎。

“搜狗”——To Be 输入法巨人

记得我第一次上网是2004年6月份中旬,那时刚刚结束高考,跟同学一起去网吧上网,第一次学会使用CTRL+SHIFT切换输入法,开始知道怎么打字,当时大部分人都在使用智能ABC打字。这个输入法一直用到大二,大三的时候开始有同学使用搜狗拼音输入法,而且迅速在班级中流传开来,当时那个爽啊!直到现在,自己的电脑上也一直用的是搜狗输入法,期间试过谷歌拼音输入法和QQ拼音输入法,觉得都不错,但是毕竟使用搜狗习惯了,最终还是选择了搜狗。

我不喜欢有广告的软件(无聊的广告),更不喜欢会弹窗体的软件,那么搜狗可以算作这一类的,之前我还会尝试使用自己曾经的搜狐账号登录一下,后来发现总是有一些我并不需要的信息,遂再也不登录了。现在经常会弹出一个窗体通知我更新了一些什么网络热词,同时还会有搜狐高清视频的一些广告,当然这些广告我一直都很不喜欢,甚至讨厌。相对这个广告来说,谷歌拼音和QQ拼音纯净的界面无广告让我觉得很清爽,但是为什么还选择搜狗呢?

  1. 习惯使然,我已经使用该输入法两年多了,早已经熟悉了它的词序排列,而且它的智能组词能力确实很突出,至少在我自己的体验山上来看,比谷歌拼音和QQ拼音好了不少,虽然这三家企业都有自己的搜索引擎,其中的谷歌更是搜索巨头,在网络热词和智能组词上都不逊色,但是问题就是这些产品都是在想搜狗学习,甚至可以说是抄袭,因为你不能跟搜狗区别太大,如果太大的话,对于其他想更换输入法的用户来说成本会太高,导致用户再度流失。既然跟在人家的屁股后头走,那么自然有很多东西要慢上一个节拍,那么用户首选的肯定不会是后者了。
  2. 轻度的广告,虽然我对软件有一定的洁癖,但是还不至于到一尘不染的境界。搜狗的广告不像某些软件,只要你登录立刻给你弹出一个窗体,一大堆的标签页,各种新闻信息扑面而来了,很可能就会打断你原本启动该软件的初衷,转而去浏览其中的一些能吸引你的信息了(如网络美女和花边新闻等等)。搜狗的广告页面保持了一个低调的态度,首先它将广告区域选择了与系统托盘靠近的右下角,这个区域并不是用户的热点区域,并不会立刻将你的视线吸引过去,其次广告页面很小,而且不需要主动关闭,在几秒钟之后自行卷帘消失,在工作中的你完全可以不予理会。第三,搜狗的广告可以隐藏在当前输入面板,例如当你输入鼠标时,在你的输入面板上方(拼音输入处)显示一个第六选项,即“到淘宝找‘鼠标’:http://search8.taobao.com/browse/search_easy.htm?keyword=%CA%F3%B1%EA&catid=11&refpid=mm_14616170_2082030_8507977&isinner=06”,只要你输入6,系统将会启动你的默认浏览器,并定位到淘宝的搜索页面,关键字为鼠标。
  3. 联想功能,同刚才的淘宝广告有点类似的是,只要你输入高考两字,同样在输入板上方有一个第六选项,网址为:http://www.sogou.com/gaokao,虽然可能我们大多时候均是通过正规的搜索引擎如Google和百度来进行搜索的,但是这种方式无疑更为一体化,至少它为我们带来了一定的便利,当然这不是我选择搜狗的主要原因。
  4. 跨平台。这个特性对我来说,让我有点欣喜如狂,因为在Ubuntu下,我对智能拼音的满足度并不是很高,因为我已经非常习惯于搜狗的智能词组功能了,智能拼音对我来说有点点残废,让我打字总是一顿顿的,感觉上厕所总被人打断的不快。当我发现搜狗云输入法的时候,我很开心,以后写博客(也就写博客的时候,严重依赖中文输入法)就可以键随心走了,达到人键合一了。之前的云输入法还不是非常的成熟,需要使用收藏标签来调用一段JavaScript代码,现在搜狗更是推出了Firefox下的插件了,只要是在Firefox下,Ctrl+Space便可以启动搜狗云输入法了,真正的跨平台,当然只要你喜欢跨浏览器也不成问题的,虽然别的浏览器暂时还没有插件(相信Chrome下不久便会有了吧),但是只需要收藏一个书签,之后点击收藏便可以在当前页面启动输入法了。

我曾经一直以为输入法是一个系统必备的软件,曾经以为搜狗输入法只是一些程序员娱乐的产物,但是,逐渐发现,这是一个互联网利器,我们总是离不开浏览器,离不开手机,离不开电脑,我们总是想发出声音,所以我们总是需要一个能让我们更快更好发出我们声音的工具,那么搜狗无疑就是一个非常出色的一位。

另外,最近公司有同事闲来无事,做了一个搜狗的皮肤,觉得还不错。其实企业皮肤定制确实是一个非常不错的idea,个性化的皮肤总是一些发烧友针对自己发烧的领域发挥,有很多动漫和卡通人物的皮肤,也有一些学校和机构的皮肤,企业的皮肤倒确实是第一次听说和见识。其实如今企业在日常的办公中,逐渐开始强调CID的概念,从办公用品的定制化和鼠标键盘上的各种公司logo,甚至团队的logo,我们看到了一个巨大的企业个性化的市场,输入法不失为一个好的切入点。logo绝对不是唯一的一个切入点,输入法最让我们着迷的是它的智能词组功能和强大的词库,你有没有因为使用输入法输入公司同事名字苦恼过,absolutely,有过。那么公司员工姓名词库是不是一个非常好的idea呢?通过公司员工信息表自动生成更新词库难道不是很好吗?

也许,搜狗有一天真的会成长为一名巨人哦。

关于JTree的一些碎碎念

本博号称关注Web2.0, Ruby/Rails,Java。但是据本人所知,到目前为止还没有任何一篇关于Java方面的文章和只言片语。作为本博的博主,确实有点大言不惭的感觉,一想到这个心中就颇不宁静啊。

其实作为一名博客,写东西的欲望一定要强烈,很多的时候我们并没有很多的素材可以写,因为生活几乎每天都是Just so so,我们谁都不想书写平淡,总想语不惊人死不休。作为博客的人们可能这种感觉更为强烈,我是一名独立博客耶,我不能人云亦云啊,我得从我的文章里抒发我的思想啊。艹,你娘的思想也就大街上小摊上的胡萝卜包子一般廉价,还装。所以呢,我们还是需要不时的刺激一下自己的神经,同时呢,也给我们伟大的祖国发育不良的国联网添加一些有趣或无趣的素材资料吧,也算是为我国早日实现四个现代化添砖加瓦了。

===========我是分割线=========

public class JTree
extends JComponent
implements Scrollable, Accessible
How to Use Trees 一节。

树中特定的节点可以由 TreePath(封装节点及其所有祖先的对象)标识,或由其显示行(其中显示区域中的每一行都显示一个节点)标识。展开 节点是一个非叶节点(由返回 false 的 TreeModel.isLeaf(node) 标识),当展开 其所有祖先时,该节点将显示其子节点。折叠 节点是隐藏它们的节点。隐藏 节点是位于折叠祖先下面的节点。所有可查看 节点的父节点都是可以展开的,但是可以显示它们,也可以不显示它们。显示 节点是可查看的并且位于可以看到它的显示区域。

这是JDK 5.0非官方中文文档中的描述,我想这个描述给我们的第一个直观印象就是这个控件应该和Windows资源管理器中的树状结构的表现是一致的。确实如此,JTree确实是用来作为树形展示使用的,因为我们在很多的数据管理和业务处理上,秉承了我们自古就袭承的分类方式,所以我们有很多的业务可能用到或者说可以用到JTree。

那么JTree怎么用的呢?这个问题我曾经问过自己很多次,还做过很多相关的工作来学习JTree的使用,记得来到北京实习做的第一个学习阶段作业就是使用公司已有的组件产品做一个叠加分析的Demo。作为一个比较友好的叠加分析工具,就肯定需要一些GIS数据处理的功能,比如打开工作空间,数据源,数据集,地图,同时还应该能简单地做一些图层删除或者地图关闭之类的基础功能。这样一来,主体的工作就是基础功能模块的实现了,只是在基础功能模块的基础上,添加一个叠加分析功能模块,而在基础功能模块中的可视化显示JTree必然是首选控件。

在实现树状加载和显示工作空间,参考公司已有的桌面产品UI设计,需要再JTree的每个节点之前添加一些图标,用于标识当前节点的数据类型,例如线数据集和面数据集的图标是有明显差异的,这样对用户的友好度会提高很多。默认的JTree使用Java默认的meta风格显示文件夹(根节点)和文件(叶节点)的图标样式,那么如何添加自定义的图标显示呢?当时我就在JTree的文档中苦苦找寻,希望自己能找到一个setIcon()的方法,最终无耻的失败鸟。后来才知道之需要自己实现一个类,实现TreeCellRenderer就可以了,重写下面这个方法(Sun就是这么排版的,我觉得这样挺好的,不要怪我占太多行了)

Component getTreeCellRendererComponent(JTree tree,

                                       Object value,
                                       boolean selected,
                                       boolean expanded,
                                       boolean leaf,
                                       int row,
                                       boolean hasFocus)

在这个方法中,它的返回值为一个Component,那么我们完全可以自由发挥了,比如返回一个JLabel。当时欣喜若狂,赶紧将代码巴拉巴拉地敲好,一看效果显著啊,根据类型不同生成不同的Icon设置给将要返回的JLabel对象就OK了。

实习的工作相对简单,当时对JTree的理解也就点到为止了。那么此次项目组需要退出Objects Java的控件,其中就有一些控件需要使用到JTree来实现,功能要求相对就复杂了不少。

需要在一个节点文本前,显示多个图标,除了用于区别节点数据类型的图标外,还需要添加几个操作图标,用于可视化节点数据的操作,那么返回一个什么呢?JPanel无疑是最好的选择,轻量化容器中的万金油。在JPanel中添加几个可视化的Icon并不是难事,只是JLabel多少的问题了,通过对节点数据类型的判断分别设置便好了。问题是,如何判断用户当前点击的位置落在JPanel中的那个操作图标上呢?又如何将这些操作直接反映到实际的数据上来呢?通过JTree.getUI()方法获取当前的JTree的UI,然后调用TreeUI.getPathBounds(JTree tree, TreePath path)方法获取当前节点的绘制区域,之后通过鼠标事件MouseEvent的getX()和getY()方法获取当前鼠标的位置信息,由于控件的编写图标的大小由自己定义,所以可以确定图标的大小和JPanel的布局(我使用的是FlowLayout,并且使用setHgap()方法将水平控件间距设置为0),通过像素坐标的计算便可以得出当前用户鼠标单击事件应该响应哪个对应索引处的动作。

在实现的过程中,还需要使用到编辑节点的功能,那么如何来做呢?首选实现TreeCellEditor接口,完全自己定制,可以避免像继承自DefaultTreeCellEditor的烦恼(因为它能满足一般需求,但是会限制你拳脚)。TreeCellEditor也有一个很嚣张的方法,号称自己要接管TreeCellRenderer的方法,就是这个啦

Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row)

重写这个方法,用来自定义编辑时的节点渲染,例如我的树形控件在编辑的时候只能编辑节点名称,那么前面的图标还是要保持与未编辑时一致的,编辑时只需要将后面的文本置换为一个JTextField就可以了。然后为该JTextField注册一个键盘事件监听器,当输入Enter的时候,调用TreeCellEditor的stopEditing()方法,触发停止编辑事件。如果我们需要将编辑保存至数据模型中的话,就在stopEditing()方法中编写业务代码即可。

综上JTree这个控件实际上是一个完全遵循MVC架构的设计,甚至比MVC还抽象一些。JTree中只处理数据和显示的一些控制,例如判断当前节点是否能够被编辑的方法isPathEditable(TreePath path)等。数据模型完全可以委托为TreeModel来管理,之需要使用setModel便可以轻松地将JTree和TreeModel关联起来。而在其显示渲染上便是完全由TreeCellRenderer来接管的,只需实现一个类,该类实现TreeCellRenderer接口,重写getTreeCellRendererComponent(…)方法,便可实现完全自定义面板显示节点。抽象最高层的是,当节点为可编辑状态时,其渲染又交由TreeCellEditor接管了,在编辑节点时,TreeCellEditor的getTreeCellRendererComponent(…)方法便将完全接管节点的渲染工作,并且控制编辑时的动作,例如取消编辑和停止编辑之类的种种。这么看来,其实JTree只是提供一个壳子,通过其内部的TreeMod存储数据,外部的TreeCellRenderer和TreeCellEditor来控制其显示渲染和编辑渲染,给开发人员提供了一个可高度定制化的控件接口。

==========我还是分割线=========

本文的形成是如行云流水账一般啊,我也有点不知所云了,众位看官,能看则看,不能看则拉倒吧。JDK API文档在你家里叫你回家翻翻呢。