Flyingis

Talking and thinking freely !
Flying in the world of GIS !
随笔 - 156, 文章 - 16, 评论 - 589, 引用 - 0
数据加载中……

2005年10月31日

Flyingis on BlogJava 停止更新

    文章在多个博客间来回拷贝切换比较麻烦,我写博客比较注重排版,格式调整也花费了不少时间,并且多个博客使得大家的讨论也分散在不同的地方,因此今后BlogJavaJavaEye上的文章停止更新(已经停止一段时间了),感谢大家一直以来的关注,今天是愚人节,但这条消息是正式声明:)

    博客园上继续保持更新,请访问:

    http://www.cnblogs.com/flyingis

    欢迎拍砖交流!

    Flyingis

posted @ 2008-04-01 11:01 Flyingis 阅读(2141) | 评论 (1)编辑 收藏

ArcGIS 9.2 SP4 补丁升级

    最近一直在出差,今天发现ArcGIS 9.2 sp4补丁已经出来了,打破了9.0三个补丁包的记录及单位时间内的补丁密度:)。如果是全新的应用系统,请直接升级,否则先参考这两篇说明:

    A complete list of the issues that have been fixed in this service pack is available here.
    A list of the main enhancements that have been made in the 9.2 Service Packs is available here.

    确认需要打上sp4补丁?那就开始吧:所有sp4补丁链接

    ArcGIS 9.2每次释放出的补丁不仅解决了许多已发现的bug,更是在功能、文档方面做了大量的改进,所以现在准备开发或正在开发的应用系统都应该尽量升级到最新补丁,避免被一些无厘头的问题扯了后腿。

posted @ 2007-12-11 23:13 Flyingis 阅读(3510) | 评论 (8)编辑 收藏

跨网段部署 ArcGIS Desktop 浮动 License

    如果单独在服务器上部署ArcGIS桌面浮动License,一般的都需要处理防火墙端口问题,这种环境在校园机房中最为典型,9.x版本需要开放27004端口,这样所有机器都可以访问到服务器上的License,但是在跨网段环境中,还需要额外的处理。

    使用Windows XP/2003自带的防火墙,除了开发27004 TCP端口外,还应将lmgrd.exe、ARCGIS.exe添加到例外程序中,其他商业防火墙同样需要放开这两个程序的访问控制,否则将无法连接到License服务器。

    如果使用的是第三方防火墙,如瑞星、天网,则只需开放27004/tcp端口。

posted @ 2007-12-11 23:12 Flyingis 阅读(2316) | 评论 (0)编辑 收藏

远程连接 SuSE Linux 设置方法

    作者:Flyingis

    且不说远程连接的便利性,就是机房里那轰轰的高分贝就足以让你的耳膜形成习惯性振动,何况还需要集中精神工作呢,在网络带宽允许的情况下,还是选择远程吧。远程连接的客户端工具有很多,有商业的如Symantec pcAnywhere等,但我用的最多的还是Xmanager、VNC、Windows自己的远程连接工具、还有Telnet,和Windows环境一样,默认情况下远程连接是没有打开的,连接SuSE Linux服务器就需要做一些设置,其他Linux服务器相仿。

    Xmanager

1. 编辑 '/etc/opt/kde3/share/config/kdm/kdmrc' file in config section '[XDMCP]'
    更改"Enable=false" to "Enable=true",将port=177的屏蔽去掉。

2. 编辑 '/etc/sysconfig/displaymanager'
    更改'DISPLAYMANAGER_REMOTE_ACCESS="no"' to 'DISPLAYMANAGER_REMOTE_ACCESS="yes"'

    然后使用rcxdm restart命令来重启xdm服务,一定要有/opt/kde3/bin/kdm进程存在,如果没有使用rcxdm restart命令看看是否能重启服务,并且用netstat -a |grep xdm来看看端口是否在listen。

    或者是,YAST中的Network Service打开Remote Administration,然后运行rcxdm restart。

    VNC

    用root用户更改/root/.vnc下的xstart文件,然后注释最后一行,再加上gnome - session &

    执行vncstart,这样就可以通过VNC连接了,如果不更改xstart文件,也可以通过vncstart打开VNC连接,但在客户端连接后出现的是命令行窗口,和ssh类似。

posted @ 2007-10-19 13:20 Flyingis 阅读(4477) | 评论 (0)编辑 收藏

分布式部署 ArcSDE 和 Oracle 服务

     摘要: 经常辗转于各种服务器之间,漂浮于各种主流操作系统(AIX/Solaris/SuSE/RH/Windows)之上,被Windows惯坏了之后面对其他环境时经常会发现自己才疏学浅,有时间还是要恶补一下这些笔记,否则下次自己又忘了~~  阅读全文

posted @ 2007-10-14 22:43 Flyingis 阅读(4159) | 评论 (1)编辑 收藏

高效率编辑器 VIM-操作篇[转载]

原文链接:http://jmcpherson.org/editing.html
翻译链接:http://linuxtoy.org/archives/efficient-editing-with-vim.html


这篇教程写了在不同工作模式下使用 VIM 的一些基本技巧——即插入模式(insert mode), 命令模式(command mode), 存取文件等。目的是帮助刚刚接触 VIM 的新手更加有效率的使用这个出色的编辑器。

说明:在这篇文章里面,<C-X> 代表 Ctrl + X——就是按住 Ctrl 键然后再按 X。而且你可以在很多情况下使用 :help command 来获得大部分命令的帮助,这个是 VIM 的内部帮助文件命令。


高效率移动

在插入模式之外

基本上来说,你应该尽可能少的呆在插入模式里面,因为在插入模式里面 VIM 就像一个“哑巴”编辑器一样。很多新手都会一直呆在插入模式里面,因为这样易于使用。但 VIM 的强大之处在于他的命令行模式!你会发现,在你越来越了解 VIM 之后,你就会花越来越少的时间使用插入模式了。

使用 h、j、k、l

使用 VIM 高效率编辑的第一步,就是放弃使用箭头键。使用 VIM,你就不用频繁的在箭头键和字母键之间移来移去了,这会节省你很多时间。当你在命令模式时,你可以用 h、j、k、l 来分别实现左、下、上、右箭头的功能。一开始可能需要适应一下,但一旦习惯这种方式,你就会发现这样操作的高效之处了。

在你编辑你的电子邮件或者其他有段落的文本时,你可能会发现使用方向键和你预期的效果不一样,有时候可能会一次跳过了很多行。这是因为你的段落在 VIM 看来是一个大的长长的行。这时你可以在按 h、j、k 或者 l 之前键入一个 g,这样 VIM 就会按屏幕上面的行如你所愿的移动了。

在当前行里面有效的移动光标

很多编辑器只提供了简单的命令来控制光标的移动(比如左、上、右、下、到行首/尾等)。VIM 则提供了很多强大的命令来满足你控制光标的欲望。当光标从一点移动到另外一点,在这两点之间的文本(包括这两个点)称作被“跨过”,这里的命令也被称作是 motion。(简单说明一下,后面会用到这个重要的概念)

这里是常用到的一些命令(motion):

  • fx:移动光标到当前行的下一个 x 处。很明显,x 可以是任意一个字母,而且你可以使用 ; 来重复你的上一个 f 命令。
  • tx:和上面的命令类似,但是是移动到 x 的左边一个位置。(这真的很有用)
  • Fx:和 fx 类似,不过是往回找。
  • w:光标往前移动一个词。
  • b:光标往后移动一个词。
  • 0:移动光标到当前行首。
  • ^:移动光标到当前行的第一个字母位置。
  • $:移动光标到行尾。
  • ):移动光标到下一个句子。
  • ( :移动光标到上一个句子。

在整个文件里面有效移动光标

VIM 有很多命令,可以用来到达文件里面你想到达的地方。下面是一些在文件里面移动的命令:

  • <C-F>:向下移动一屏。
  • <C-B>:向上移动一屏。
  • G:到文件尾
  • numG:移动光标到指定的行(num)。(比如 10G 就是到第 10 行)
  • gg:到文件首
  • H:移动光标到屏幕上面
  • M:移动光标到屏幕中间
  • L:移动光标到屏幕下面
  • *:读取光标处的字符串,并且移动光标到它再次出现的地方。
  • #:和上面的类似,但是是往反方向寻找。
  • /text:从当前光标处开始搜索字符串 text,并且到达 text 出现的地方。必须使用回车来开始这个搜索命令。如果想重复上次的搜索的话,按 n。
  • ?text:和上面类似,但是是反方向。
  • ma:在当前光标的位置标记一个书签,名字为 a。书签名只能是小写字母。你看不见书签的存在,但它确实已经在那里了。
  • `a:到书签 a 处。注意这个不是单引号,它一般位于大部分键盘的 1 的左边。
  • `.:到你上次编辑文件的地方。这个命令很有用,而且你不用自己去标记它。

高效的输入

使用关键词自动完成

VIM 有一个非常漂亮的关键词自动完成系统。这表示,你可以输入一个长词的一部分,然后按一下某个键,然后 VIM 就替你完成了这个长词的输入了。举个例子:你有一个变量名为 iAmALongAndAwkwardVarName 在你写的代码的某个地方。也许你不想每回都自己一个一个字母的去输入它。

使用关键词自动完成功能,你只需要输入开始几个字母(比如 iAmAL),然后按 <C-N>(按住 Ctrl,再按 N)或者 <C-P>。如果 VIM 没有给出你想要的词,继续按,直到你满意为止,VIM 会一直循环它找到的匹配的字符串。

聪明的进入插入模式

很多新手进入插入模式都只是用 i。这样当然可以进入插入模式,但通常不是那么合适,因为 VIM 提供了很多进入插入模式的命令。下面是最常用的一些:

  • i:在当前字符的左边插入
  • I:在当前行首插入
  • a:在当前字符的右边插入
  • A:在当前行尾插入
  • o:在当前行下面插入一个新行
  • O:在当前行上面插入一个新行
  • c{motion}:删除 motion 命令跨过的字符,并且进入插入模式。比如:c$,这将会删除从光标位置到行尾的字符并且进入插入模式。ct!,这会删除从光标位置到下一个叹号(但不包 括),然后进入插入模式。被删除的字符被存在了剪贴板里面,并且可以再粘贴出来。
  • d{motion}:和上面差不多,但是不进入插入模式。

有效的移动大段的文本

使用可视选择(visual selections)和合适的选择模式

不像最初的 VI,VIM 允许你高亮(选择)一些文本,并且进行操作。这里有三种可视选择模式:

  • v:按字符选择。经常使用的模式,所以亲自尝试一下它。
  • V:按行选择。这在你想拷贝或者移动很多行的文本的时候特别有用。
  • <C-V>:按块选择。非常强大,只在很少的编辑器中才有这样的功能。你可以选择一个矩形块,并且在这个矩形里面的文本会被高亮。

在选择模式的时候使用上面所述的方向键和命令(motion)。比如,vwww,会高亮光标前面的三个词。Vjj 将会高亮当前行以及下面两行。

在可视选择模式下剪切和拷贝

一旦你高亮了选区,你或许想进行一些操作:

  • d:剪贴选择的内容到剪贴板。
  • y:拷贝选择的内容到剪贴板。
  • c:剪贴选择的内容到剪贴板并且进入插入模式。

在非可视选择模式下剪切和拷贝

如果你很清楚的知道你想拷贝或者剪切什么,那你根本就不需要进入可视选择模式。这样也会节省时间:

  • d{motion}:剪切 motion 命令跨过的字符到剪贴板。比如,dw 会剪切一个词而 dfS 会将从当前光标到下一个 S 之间的字符剪切至剪贴板。
  • y{motion}:和上面类似,不过是拷贝。
  • c{motion}:和 d{motion} 类似,不过最后进入插入模式。
  • dd:剪切当前行。
  • yy:拷贝当前行。
  • cc:剪切当前行并且进入插入模式。
  • D:剪切从光标位置到行尾到剪贴板。
  • Y:拷贝当前行。
  • C:和 D 类似,最后进入插入模式。
  • x:剪切当前字符到剪贴板。
  • s:和x类似,不过最后进入插入模式。

粘贴

粘贴很简单,按 p。

使用多重剪贴板

很多编辑器都只提供了一个剪贴板。VIM 有很多。剪贴板在 VIM 里面被称为寄存器(Registers)。你可以列出当前定义的所有寄存器名和它们的内容,命令为“:reg”。最好使用小写字母来作为寄存器的名称,因为大写的有些被 VIM 占用了。

使用寄存器的命令为双引号 “。

比如:我们要拷贝当前行到寄存器 k。你应该按 “kyy。(你也可以使用 V”ky。为什么这样也可以呢?)现在当前行应该已经存在了寄存器 k 里面直到你又拷贝了一些东西进入寄存器 k。现在你可以使用命令 “kp 来粘贴寄存器 k 里面的内容到你想要的位置。

避免重复

令人惊奇的 . 命令

在 VI 里面,输入 . (小数点符号),将会重复你输入的上一个命令。比如,你上个命令为“dw”(删除一个词),VI 将会接着再删除一个词。

使用数字

使用数字也是 VIM 强大的而且很节省时间的重要特性之一。在很多 VIM 的命令之前都可以使用一个数字,这个数字将会告诉 VIM 这个命令需要执行几次。比如:

  • 3j 将会把光标向下移动三行。
  • 10dd 将会删除十行。
  • y3″ 将会拷贝从当前光标到第三个出现的引号之间的内容到剪贴板。

数字是扩展 motion 命令作用域非常有效的方法。

记录宏

有时候,你会发现你自己在文章的每段或者每行都重复相同的一系列动作。VIM 允许你记录一个宏来完成你的特殊需要。

  • qregister:记录宏到寄存器 register,这里 register 是任意的你的寄存器的名字。比如 qa,将会记录并且把宏存在寄存器 a 里面。
  • q:结束宏的记录。
  • @register:使用存在寄存器 register 的宏。比如 @a,将会使用存在寄存器 a 里面的宏。

必须要记住的是,宏只记录了你的系列按键并且重复执行它们。它们不是魔法。因为在 VIM 里面完成目的的方法有很多,所以有时候你要小心选择命令来记录你的宏。因为它们会在所有你要执行它的地方执行。

用 VIM 写代码

VIM 是一个用来写代码的绝好编辑器,因为它有一些特性是专门为程序员而设计的。这里是一些常用的:

  • ]p:和 p 的功能差不多,但是它会自动调整被粘贴的文本的缩进去适应当前代码的位置。试一下!
  • %:匹配花括号、方括号、括号等。在一个括号的上面,然后按 %,鼠标就会出现在匹配的另外一半括号处。
  • >>:缩进所有选择的代码
  • <<:和上面类似,但是反缩进
  • gd:到达光标所在处函数或者变量的定义处。
  • K:在 Man 里面查找光标当前所在处的词。

posted @ 2007-09-16 14:10 Flyingis 阅读(3408) | 评论 (0)编辑 收藏

AIX 和 Linux 基于 NFS 实现共享

     摘要: 这是ArcIMS在SuSE和AIX(1 suse+n aix)上分布式部署时的一个细节。  阅读全文

posted @ 2007-09-12 14:47 Flyingis 阅读(4458) | 评论 (0)编辑 收藏

又一个升级补丁引发的 arcgisserver cache 问题

    成功创建了地图cache或将arcgis server补丁升级到最新版本后,出现arcgis catalog及web应用程序不能识别的情况,这是由于arcgis桌面软件和arcgis server的补丁不是同一个版本造成的,如server已经升级到9.2 sp3,arcgis desktop还是sp2,解决方法就是将软件补丁版本同步。

    大家都知道不同版本的ArcGIS软件不能安装在同一台计算机上,如Desktop 9.1和ArcGIS Engine 9.2不能共存,在一台计算机上必须保证版本一致,其实同一版本下的补丁也是一样,ESRI官方网站释放出补丁时都会有说明,所以尽量不要被这种问题拖了后腿:)

posted @ 2007-09-07 18:04 Flyingis 阅读(2406) | 评论 (0)编辑 收藏

升级 ArcGIS Server 9.2 sp3 补丁

    作者:Flyingis

    下午花了一个半小时打上了ArcGIS 9.2 sp3全套补丁,现在ESRI发布补丁的速度大大快于以往,打补丁的速度越来越慢,这从侧面反应出了程序存在的bug,但相对于9.2刚刚发步的时候,现在sp3已经完善许多了。

    ArcGIS Server 9.2 sp3解决了不少问题,强烈推荐最新使用server开发的项目先打上补丁,原有的9.2程序也可以运行在新补丁的环境中,暂时没碰到什么问题,但是如果做了大量的cache,升级sp3补丁的时候就需要注意了!

    因为server补丁升级后会进行post installation,重新指定arcgisserver目录,该目录下所有文件的权限都会进行一次更新,如果之前生成了大量cache,更新权限会消耗大量的时间和计算机资源,以至于感觉计算机宕机,因此需要采用其他办法来解决这个问题——偷梁换柱,再换回:)

1.停止server服务。
2.重命名现有的arcgisserver文件夹。
3.进行post installation,注销重新登录计算机,再次停止server服务(post后服务会自动启动)。
4.删除post后生成cache目录。
5.将原来arcgisserver备份文件夹中的cache目录移动到post生成的arcgisserver目录中。
6.重新启动server服务。

    OK,这样就省事了。

    参考:ESRI Support, Article ID 32766

posted @ 2007-09-04 16:45 Flyingis 阅读(2829) | 评论 (1)编辑 收藏

ArcGIS Server 开发系列(二)--Web ADF 编程

     摘要: 目标:
根据查询语句实现图层信息查询
准备工作:
1.Windows XP sp2中/英文版
2.Visual Studio 2005中/英文版
3.ArcGIS Server 9.2(我打上了sp2补丁),创建一个ArcGIS Server服务,Map Server属性中更改Pooling,使用池化连接方式,Progresses选择“In a seperate process for each instance(high isolation)”,我的服务为“World”
4.利用vs2005创建一个模板server应用--Web Mapping Application,并更改MapResourceManager属性  阅读全文

posted @ 2007-08-14 13:55 Flyingis 阅读(7110) | 评论 (10)编辑 收藏

ArcGIS Server 开发系列(一)--编程框架总览

     摘要: 理论性的描述总是让人觉得有点枯燥,但是做ArcGIS Server编程,不论是用.Net ADF还是Java ADF,都需要对Server开发的基本框架有所了解,这样在后面的代码编写中才能逐步理解这些架构的设计思想。  阅读全文

posted @ 2007-08-09 15:54 Flyingis 阅读(6506) | 评论 (2)编辑 收藏

ESRI 发布 ArcGIS 9.2 sp3

    很准时,2007年8月1日ESRI发布了ArcGIS 9.2 sp3补丁,相对于美国时间就是7月的最后一天,大家可以到ESRI官方网站上去下载,至于补丁所包含最新的改进可以参考上篇文章:http://www.blogjava.net/flyingis/archive/2007/07/17/130822.html

posted @ 2007-08-07 15:28 Flyingis 阅读(2483) | 评论 (0)编辑 收藏

ArcGIS 9.2 Service Pack 3 - Announcement

     摘要: ESRI网站上已经帖出ArcGIS 9.2 sp3的说明,提供下载的时间就是本月底了,看看有哪些更新。
http://support.esri.com/index.cfm?fa=downloads.patchesServicePacks.viewPatch&PID=17&MetaID=1319  阅读全文

posted @ 2007-07-17 14:26 Flyingis 阅读(11040) | 评论 (0)编辑 收藏

AE92 for Java 中手动释放 COM 对象

    作者:Flyingis 

    用Java进行ArcEngine或ArcGIS Server开发,在底层实际上是用Java调用AO COM对象,ESRI用Jintegra库来解决Java对COM的调用问题,如果Java对象不再使用,Java虚拟机会自动将这些对象回收,然后 Jintegra将这些对象所指的实际COM对象销毁,默认情况下时间间隔是10秒,对于快速大量调用COM对象的操作来说,如在循环中,COM对象往往得不到及时的销毁,以至于内存报错,这时我们需要手动销毁COM。

    Jintegra释放方法:

    com.linar.jintegra.Cleaner.release(objectRef);

    在ArcEngine和ArcGIS Server中如何释放COM呢?Jintegra为ArcObjects生成了一组proxy类,可以参考com.esri.arcgis.interop命名空间,经常用的是 com.esri.arcgis.interop.Cleaner,它的release(java.lang.Object anObject)和releaseAll()用来释放指定的或所有的COM对象,同时可以为COM连接和释放增加监听, addConnectionListener(ConnectionListener listener)和allUnreferencedListener(Unreferenced listener)。

    同时可以参考:

    HowTo:  Explicitly release a COM object accessed in a Java application
    J-Integra for COM Document
    Garbage Collection: Releasing Java References to COM Objects
    Java调用COM的中间件Jintegra初探

posted @ 2007-07-09 14:10 Flyingis 阅读(3672) | 评论 (1)编辑 收藏

ArcIMS[err0143] 解决方法

     摘要: "Unable to display mapservice:[err0143] server not available for service ...",这是出现错误时网页的提示,应该如何解决这个问题呢?请继续往下看……  阅读全文

posted @ 2007-06-29 13:49 Flyingis 阅读(4486) | 评论 (0)编辑 收藏

ArcGIS Server 体系结构

     摘要: ArcGIS Server包含两个重要部分,一个是ArcGIS Server服务器端(SOM/SOCs),另外就是用于客户端开发的ADF(Application Developer Framework)程序集,包括adf for java和adf for .net。在掌握ArcGIS Server开发之前,先看看ArcGIS Server的体系架构。  阅读全文

posted @ 2007-06-29 09:20 Flyingis 阅读(5728) | 评论 (3)编辑 收藏

ArcGIS Desktop 9.2 非版本编辑

    作者:Flyingis

    ArcGIS Desktop 9.2开始支持非版本编辑,和标准的数据库事务处理一样,ArcSDE非版本编辑直接对原数据进行编辑,非版本编辑的session不保存任何对数据的更改,在ArcMap中对数据start edit,然后对数据进行增、删、改,或是修改属性信息,完成后执行save edit就可以将Geodatabase中的数据直接更新,否则edit session without saving放弃之前的修改。在这种模式下处理数据会存在一些问题,如当某一段编辑过程中出现问题时不能放弃或恢复修改,要么只能退出整个session的编辑放弃所有的修改。

    使用ArcSDE非版本编辑可以针对简单数据进行处理--点、线、面、注记、relationship,如果feature class存在于拓扑或网络中,则不能进行编辑。

    ArcMap中进行非版本编辑需要注意:

    1.数据已经registered with the geodatabase

    所有ArcGIS Desktop创建的数据会自动registered with the geodatabase,只有当数据是在ArcGIS Desktop外创建时(如sdetable命令创建)才需要手动注册。一般我们可以在ArcCatalog中看到空间数据的Register with Geodatabase为灰色的。

    2.数据没有registered as versioned

    如果数据已经注册为版本,可以unregister as versioned,这时之前该版本中没有提交的数据会丢失。

    3.配置ArcMap编辑进程的属性

    取消“Edit a version of the database with the ability to undo and redo”选项。

    编辑非版本Geodatabase数据库中的数据,需要注意DBMS的一些特性:同步与锁、隔离机制、数据完整性等,以后再说吧。

posted @ 2007-06-25 22:49 Flyingis 阅读(2882) | 评论 (3)编辑 收藏

[Design Pattern] The Factory Pattern

     摘要: 对工厂模式的重复罗嗦,用Factory生产Thinkpad。  阅读全文

posted @ 2007-06-17 15:01 Flyingis 阅读(3603) | 评论 (2)编辑 收藏

SuSE 9.1 平台 ArcIMS(JRE) 中文显示解决方案

     摘要: 最初以为是操作系统的字体显示问题,但SuSE9.1本身是包含中文字体的,很容易让我们想到了JRE。

文章标题为《SuSE 9.1 平台 ArcIMS 中文显示解决方案》,ArcIMS运行于JRE环境之上,因此问题的根本在于SuSE9.1平台下JRE运行时环境的中文显示,通过文中介绍的方案可以解决SuSE9.1操作系统中运行于JRE之上的所有应用程序的中文显示问题,如ArcIMS Author打开SDE空间数据库时以中文命名的表无法显示,数据属性字段中的中文显示为乱码等等。  阅读全文

posted @ 2007-05-28 09:29 Flyingis 阅读(3707) | 评论 (1)编辑 收藏

Spatial Reference

     摘要: 空间参考是GIS的基础,失去了空间参考信息,地理空间内所有的信息也就失去了存在的意义,因为它们是不准确的或是错误的。看看ArcGIS9.2对于Spatial Reference的描述及如何编程实现。

文章中代码使用C#描述,AE92 for Java SDK的com.esri.arcgis.geometry中各种接口、实现方式和C#基本一致,可以使用相同的思路来解决AE Java开发中关于Spatial Reference的问题。  阅读全文

posted @ 2007-05-10 14:43 Flyingis 阅读(5021) | 评论 (2)编辑 收藏

ArcSDE 9.1 在 Windows 平台双机热备

     摘要: 一直没有时间整理各种平台下ESRI软件安装文档,只能简单描述一下,有什么问题可以留言。  阅读全文

posted @ 2007-04-24 09:32 Flyingis 阅读(3095) | 评论 (2)编辑 收藏

Geometry 对象浅析

     摘要: ArcEngine Geometry库定义了基本几何图形的矢量表达形式,顶级的几何图形有Points、Multipoints、Polylines、Polygons、Multipatches,Geodatabase和绘图系统使用这些几何图形来定义其他各种形状的特征和图形,提供了编辑图形的操作方法和地图符号系统符号化特征数据的途径。

文章中代码使用C#描述,AE92 for Java SDK的com.esri.arcgis.geometry中各种接口、实现方式和C#基本一致,可以使用相同的思路来解决AE Java开发中关于Geometry的问题。  阅读全文

posted @ 2007-04-19 14:15 Flyingis 阅读(4907) | 评论 (4)编辑 收藏

ArcGIS 9.2 SP2 补丁开始提供下载

2007年4月16日ESRI正式发布ArcGIS 9.2 SP2补丁下载

ArcGIS 9.2 Service Pack 2
(包括ArcGIS Desktop、ArcGIS Desktop开发包、ArcEngine SDK、ArcEngine Runtime、ArcGIS Server、ArcGIS Server WebADF Runtime升级补丁包)
http://support.esri.com/index.cfm?fa=downloads.patchesServicePacks.viewPatch&PID=66&MetaID=1270

ArcIMS 9.2 Service Pack 2
http://support.esri.com/index.cfm?fa=downloads.patchesServicePacks.viewPatch&PID=16&MetaID=1271

ArcSDE 9.2 Service Pack 2
http://support.esri.com/index.cfm?fa=downloads.patchesServicePacks.viewPatch&PID=66&MetaID=1269

SP补丁体积不断增加似乎是当今软件发展的趋势,这次释放出的升级包中,桌面帮助、Server等升级包都超过了200M,补丁升级过程耗时也较长,准备升级之前需做好重要数据备份,参考网站上的说明进行。

ArcGIS 9.2 SP2补丁的改进,请参考这里:
http://downloads.esri.com/support/downloads/other_/ArcGIS-92sp2-issues.htm
http://downloads.esri.com/support/downloads/ims_/ArcIMS_92sp2_issues.htm
http://gisupdates.esri.com/92sp2/ArcSDE-Windows-UNIX-Linux/ArcSDE-92sp2-issues.htm

posted @ 2007-04-17 10:06 Flyingis 阅读(4720) | 评论 (0)编辑 收藏

用多边形裁剪影像文件

     摘要: 裁剪方式分为矩形裁剪和多边形裁剪。  阅读全文

posted @ 2007-04-12 11:23 Flyingis 阅读(4866) | 评论 (1)编辑 收藏

Geoprocessing 消息机制

    作者:Flyingis

    ArcToolbox每个工具执行之后,都会向Geoprocessor返回消息,包括操作何时开始,使用哪些参数,操作的进度,以及可能出现的问题和错误。消息的种类包括常规消息、警告、错误,GPMessage类可以包含消息的文本及严重等级。

    首先,Geoprocessor.getMessage()方法可以捕获最后一个工具执行后返回的错误消息

String messages = gp.getMessages(2);
System.out.println(messages);

    如何使用GPMessage

//if there was an error then you want to loop the messages
//returned by the geoprocessor to look for the error
GPMessages gpMessages = (GPMessages)gp.getReturnMessages();
for(int i = 0;  i gpMessages.getCount(); i++{
      System.out.println(gpMessages.getMessage(i).getDescription());
}

    可以看出,上面都是通过GeoProcessor的方法来获取消息,除此之外还可以使用IGeoProcessorResult接口,从功能上来说它们没有多少区别。

// Execute Union
IGeoProcessorResult pResult = gp.execute(uniontool, null); 
if (pResult.getMessageCount() > 0)  
      
for(int i = 0;  i <= pResult.getMessageCount() - 1; i++){
            System.out.println(pResult.getMessageCount());
      }

}

    另外我们还可以自定义输出的方法,根据程序执行的过程,可以添加的方法有AddMessage、AddWarning、AddError。下面的示例将feature class从一个工作区复制到另外一个工作区,并跟踪显示每个文件复制的情况。

IGpEnumList fcs = gp.listFeatureClasses("""","");
Copy copy 
= new Copy();
String fc 
= fcs.next();
while (! "".equals(fc)){
      gp.addMessage(
"Copying " + fc + " to file gdb" );
      copy.setInData(fc);
      copy.setOutData(
"C:/temp/eric.gdb" + "/" + fc);
      
try {
            gp.execute(copy, 
null);
      }
 catch (Exception e) {
            gp.addError(
"COPY FAILED! " + gp.getMessage(2));
      }

      fc 
= fcs.next();
}

posted @ 2007-04-10 15:58 Flyingis 阅读(3567) | 评论 (0)编辑 收藏

Geoprocessing 数据批处理

     摘要: ArcGIS使用者经常要面对大量的数据处理工作,如果要在自己的程序中使用Geoprocessing,更多的时候我们是要进行对数据进行批处理分析,Geoprocessing为我们提供了丰富的批处理的功能。  阅读全文

posted @ 2007-04-05 15:07 Flyingis 阅读(4487) | 评论 (2)编辑 收藏

Vi 指令大全[转载]

     摘要: 方便自己查阅,转载Vi指令大全。  阅读全文

posted @ 2007-04-05 10:25 Flyingis 阅读(2847) | 评论 (0)编辑 收藏

学习在 ArcEngine 中使用 Geoprocessing

     摘要: Geoprocessing对于ArcGIS使用者来说,是一种非常方便实用的工具,它可以利用ArcToolbox中的各种工具为我们的地理空间工作流进行框架建模,自动执行空间分析与处理。现在ArcEngine 9.2单独提供了com.esri.arcgis.geoprocessing.tools工具包,使得在二次开发中通过Geoprocessing构建应用模型,将ArcGIS众多分析工具集成到我们的应用中成为现实。看看在ArcEngine for Java环境中如何使用它。  阅读全文

posted @ 2007-04-04 17:23 Flyingis 阅读(8926) | 评论 (1)编辑 收藏

ArcGIS 9.1 升级到 9.2 部分文件格式不可读的解决方法

     摘要: 机器上安装了ArcGIS 9.1和Erdas Image,卸载ArcGIS 9.1安装新版本9.2,发现img、tif、grid格式的文件均不可读,其中打开img文件的时候提示"Raster Objects Data Error",卸载ArcGIS 9.2重装ArcGIS 9.1,问题依旧。本文提供了解决方法。  阅读全文

posted @ 2007-03-15 17:21 Flyingis 阅读(3847) | 评论 (2)编辑 收藏

AE92 SDK for Java 窗体简例

     摘要: 看看怎么用AE92 SDK for Java做简单的窗体应用。  阅读全文

posted @ 2007-03-09 12:41 Flyingis 阅读(4940) | 评论 (2)编辑 收藏

AE92 SDK for Java 最小示例学习

     摘要: ArcEngine 92 SDK for Java 最小示例学习,类似于Java开发的第一个例子"Hello World",但要稍微复杂一点。整个过程清晰明了,通过这个例子我们可以顺藤摸瓜,逐渐深入到AE的开发中。  阅读全文

posted @ 2007-03-08 16:21 Flyingis 阅读(3631) | 评论 (0)编辑 收藏

ArcGIS 坐标系统文件

     摘要: 看看ArcGIS 9.2中包含的坐标系统文件夹Geographic Coordinate Systems、Projected Coordinate Systems、Vertical Coordinate Systems的简介,欣赏北京54和西安80投影坐标系令人费解的命名方式。  阅读全文

posted @ 2007-03-02 09:04 Flyingis 阅读(13923) | 评论 (7)编辑 收藏

地震为什么没有影响到 Google

原文链接:http://news.mydrivers.com/pages/20070120074305_14081.htm

2006年底,台湾海域地震,让人们深刻感觉到互联网的脆弱。在这次地震中,中美海缆、亚太一号、亚太二号海缆、FLAG海缆、亚欧海缆、FNAL海缆等多条国际海底通信光缆中断。一时间,台湾,韩国,日本,菲律宾,甚至印度的呼叫中心都受牵连;中国用户几乎无法访问所有的美国网站以及网络服务,有些网站虽然可以勉强登入,但速度也让人无法忍受。

不过,与平时经常被“屏蔽”相反,Google在此期间几乎没有受到影响,搜索引擎、Gmail以及Google旗下的其他服务都能够在国内正常访问。

事实上,连接中国与亚洲、美国以及欧洲的电缆有多个系统。台湾地震只损害了一部分海底电缆,但并不是所有的电缆都出现了问题。这个时间段内,从中国接入国际互联网的服务,就取决于提供该服务的这个互联网公司或者ISP购买的是哪些电缆系统,在地震中是否受到损害。

不过,还有另外一种情况存在:一些国际连接虽然没有受到地震的影响,但是过多地负载了从其它损害的电缆转道而来的信息流量,导致交通堵塞。

Google使用了多网络连接系统,如果某个数据中心出了访问障碍,系统会自动选择其它的网络路径,由其它数据中心无缝地提供服务。

在设计和实施时,Google在中国的服务网络充分考虑了冗余要求,不会因为其它线路的拥挤而变得缓慢。因此,Google中国用户感觉不到任何地震引起的变化。

为什么Google成为此次地震事件中的特例?

时间追溯到2002年2月,Google的一个数据中心的主电源跳闸,导致Google瘫痪了将近1个小时。有了这次教训,Google便彻底改变了自己的文件系统分布。

改进后的Google文件分布系统,即便一个拥有80台电脑的支架被断开连接,也能迅速完成再一次的备份,而且,并不中断正常的服务。实际上,按照霍茨勒的说法,Google的“每台服务器都有50个备份”。除此之外,多网络连接模式应用,也为服务稳定提供了有效的硬件基础。

posted @ 2007-01-20 14:54 Flyingis 阅读(2110) | 评论 (1)编辑 收藏

shapefile 和 MapGIS 文件格式之间的转换

     摘要: 这篇文章比较老了,还是在ArcGIS 8.3平台下做的,这段时间一些朋友经常问到这个问题,现在大家早已进入ArcGIS 9.x时代,但还是可以参考一下,是否适用尚不知道,如有什么变化,欢迎大家写在后面。  阅读全文

posted @ 2007-01-19 09:17 Flyingis 阅读(4593) | 评论 (2)编辑 收藏

全套 ArcGIS 软件安装(Windows 平台)

     摘要: 虽然是Windows平台下的安装,但有时也经常碰到棘手的问题,文章记录的过程比较简单,如果大家有什么疑问可以在后面留言。
关于ESRI产品的安装,以后还会写,包括各种平台下的,各种软件搭配环境下的,有些我自己也是在学习的过程中,欢迎大家一起讨论。  阅读全文

posted @ 2007-01-17 15:03 Flyingis 阅读(3568) | 评论 (0)编辑 收藏

GeoTools 2.3.0 release available for download

2 January 2007 - GeoTools 2.3.0 release brings together a lot of great improvements made over the last year. The main focus of this release is improving the raster story for GeoTools. While plug-ins for a variety of rasters existed previously, all of them were memory constrained and not really suitable for real software.

GeoTools 2.3.0 is available for download at:
http://geotools.codehaus.org/2.3.0

2.3.0 brings solid, scalable, fast support for ArcGrid, GeoTiff, GTOPO30, World Images and Image Mosaics and Pyramids. These are already in action in GeoServer 1.5.x, and will soon work their way into uDig (http://udig.refractions.net). In addition it offers:

- GeoAPI filter interfaces aligned with Filter 1.1 specification
- Completed providence review
- More relaxed PostGIS support, able to handle older varied configurations
- Scalar Vector Graphics "Marks" can be used as part of our SLD support
- Improved plug-in visibility
- Maven "archtype"
- Numerous small bug fixes and improvements

The following organizations, have contributed to this stable release: GeoSolutions for their RnD contributions appearing in this release, and OSGeo Foundation for their support during the incubation process.

- About GeoTools
GeoTools is an open source java GIS toolkit. Used for OGC based projects via GeoAPI interfaces. It includes two great SLD based renderers, raster access and reprojection. Plugins for Shapefile, ArcGrid, ArcSDE, Postgis, OracleSpatial, MySQL and many more.

For more information visit:

- http://docs.codehaus.org/display/GEOTOOLS
- http://docs.codehaus.org/display/GEOTOOLS/Mailing+Lists
- http://docs.codehaus.org/display/GEOTOOLS/Module+Matrix
- http://docs.codehaus.org/display/GEOS/GeoServer+1.5.0+beta1

Source :
http://sourceforge.net

From : http://www.gisdevelopment.net/news/viewn.asp?id=GIS:N_axrmhogkef

posted @ 2007-01-10 22:25 Flyingis 阅读(1861) | 评论 (0)编辑 收藏

静态设计

     摘要: 重新看看静态设计的优劣之处。  阅读全文

posted @ 2006-12-27 16:16 Flyingis 阅读(2449) | 评论 (0)编辑 收藏

初学 Eclipse RCP

     摘要: 以前一直做WebGIS方面的工作,对桌面关心甚少。桌面开发让人第一个想到的是VB6的快速开发,以及VC++平台中对效率的追求,VB.NET似乎找不到一个合适的定位。自己以后想逐步转向桌面,毕竟桌面才是GIS的天下,在效率、可扩展性、开发速度以及平台可持续发展中权衡,让我选择了Eclipse RCP。  阅读全文

posted @ 2006-12-13 19:22 Flyingis 阅读(3480) | 评论 (1)编辑 收藏

乱谈 GIS 中小型应用

     摘要: 文章围绕ESRI的产品讨论。
GIS中小型应用,是采用ArcEngine+ArcIMS+ArcSDE+Oracle等豪华配置,还是有其他方案可以选择?  阅读全文

posted @ 2006-11-28 22:14 Flyingis 阅读(4099) | 评论 (10)编辑 收藏

ArcSDE 中空间数据的备份与恢复 [转载]

原文链接:http://www.gis8.net/Article/arcgis/200611/362.htm

随着GIS应用系统在复杂性、集成性、并发性等方面的要求不断增加,系统所需的空间数据量在急剧地增长,同时用户对空间数据并发访问的需求也越来越突出。以传统的文件形式存储和表示空间数据的方法显然已经无法满足这些需求。由于ArcSDE本身所具有的海量数据存储、多用户并发访问、版本管理、长事务处理等强大优势,在GIS应用系统中引入ArcSDE作为空间数据存储和管理引擎,变得越来越普遍。ArcSDE作为空间数据库引擎,在ArcGIS 8.1系列软件中属于服务器端的产品,在整个产品框架中,处于数据中心的重要地位,它利用Oracle、DB2、SQL Server、Informix等关系型数据库在数据存储、数据完整性等方面的先进技术手段,将海量空间数据(包括矢量数据和栅格数据)有机地组织和管理起来,通过其内部异步缓冲、空间索引等先进的机制,提供对空间数据的多用户高效并发访问。

除了存储空间数据并提供访问,对于空间数据的备份和恢复,是空间数据管理中最重要的工作环节之一,也是保障空间数据安全的重要方式。首先,空间数据本身在应用过程中不断地被更新变动,所以经常会需要备份不同时期,不同的空间数据版本;第二,存储介质的意外损坏会导致严重的空间数据丢失,因此需要定期对空间数据对象的整体进行完全备份;第三,有时出于调整的必要,需要在不同服务器、甚至不同数据库管理系统之间进行空间数据的移植和转换。

在采用文件形式空间数据的时代,空间数据的备份仅仅是操作系统中的文件拷贝、备份和归档的过程;而空间数据的恢复也不过是复制、覆盖的操作;在基于ArcSDE和关系型数据库的空间数据库时代,空间数据的备份更多的依赖于关系型数据库的备份和恢复技术,当然也不能缺少ArcSDE所提供的备份工具。按照备份的方式和对象,ArcSDE中空间数据的备份和恢复可以分为如下两类:指定空间数据对象的备份恢复,和整体空间数据库的备份恢复。

一、 指定空间数据对象的备份和恢复
这种方式主要用于备份指定的空间数据对象,比如某个图层和要素类、其中的某些满足特定条件的记录、甚至特定的版本。实现这种备份方式的方法主要是利用ArcSDE提供的管理工具:sdeexport和sdeimport命令。它们的位置在%ArcSDEHOME%\bin\中。其中,sdeexport用于将空间数据从ArcSDE Server上备份为单独的数据文件,而sdeimport用于将经由sdeexport备份的数据文件恢复到ArcSDE Server中。

这一方式的缺点在于不能一次备份完整的空间数据库。但是也有个明显的优点,在于通过sdeexport和sdeimport工具,可以将空间数据在不同的关系型数据库管理系统(RDBMS)之间进行移植。

1. 备份全部记录
使用sdeexport命令的缺省方式即可,比如:
(1) 将指定的图层备份到备份文件
sdeexport -o create -l dcxq,shape -f d:\dcxq.exp -i jerry_oracle -u sde -p sde
就是将名为jerry_oracle的sde服务(ArcSDE for Oracle8i)中的指定图层“dcxq”按缺省方式备份到文件d:\dcxq.exp中。
(2) 利用操作系统命令,拷贝备份文件到目标服务器上
(3) 将备份文件恢复至目标RDBMS中
sdeimport -o create -l newDcxq,shape -f d:\dcxq.exp -i jerry_sqlsvr -u sde -p sde
此操作将备份文件恢复到名为jerry_sqlsvr的sde服务(ArcSDE for SQLServer)中,图层名为:newDcxq。

2. 备份部分记录
sdeexport命令中添加-w参数和一个条件选择表达式即可,比如:
(1) 将指定图层中满足条件的记录备份到备份文件
sdeexport -o create -l dcxq,shape -f d:\dcxq.exp -w xzqy = '徐汇区' -i jerry_oracle -u sde -p sde
就是将名为jerry_oracle的sde服务(ArcSDE for Oracle8i)内的指定图层“dcxq”中所有"徐汇区"的人口调查小区备份到文件d:\dcxq.exp中。
(2) 利用操作系统命令,拷贝备份文件到目标服务器上
(3) 将备份文件恢复至目标RDBMS中
sdeimport -o create -l XHDcxq,shape -f d:\dcxq.exp -i jerry_sqlsvr -u sde -p sde
此操作将备份文件恢复到名为jerry_sqlsvr的sde服务(ArcSDE for SQLServer)中,图层名为:XHDcxq。

3. 备份特定数据版本
sdeexport命令中添加-v参数和一个版本名称即可,比如:
(1) 将指定图层的特定版本备份到备份文件
sdeexport -o create -l dcxq,shape -f d:\dcxq.exp -V verAPR -i jerry_oracle -u sde -p sde
此操作将名为jerry_oracle的sde服务(ArcSDE for Oracle8i)内的指定图层“dcxq”的verAPR版本备份到文件d:\dcxq.exp中。
(2) 利用操作系统命令,拷贝备份文件到目标服务器上
(3) 将备份文件恢复至目标RDBMS中
sdeimport -o create -l APRdcxq,shape -f d:\dcxq.exp -i jerry_sqlsvr -u sde -p sde
此操作将备份文件恢复到名为jerry_sqlsvr的sde服务(ArcSDE for SQLServer)中,图层名为:APRDcxq。

二、 整体空间数据库的备份和恢复
ArcSDE空间数据库的整体备份和恢复,实质上很大程度上是其所在的数据库或者数据库对象的备份和恢复问题。当然完整的ArcSDE数据备份应当还包括dbtune.sde,giomgr.defs,dbinit.sde和services.sde等文件。

数据库的备份和恢复有很多种类。在不同的数据库管理系统中,更是千差万别。总体上,大都可以分为静态转储和动态转储两个类型。静态转储是在系统中无事务处理时进行的转储操作,因而这种方式得到的一定是一个数据一致性的副本。静态转储的优点是操作简单,保证数据一致性,但是缺点也很明显,转储操作必须等待用户事务结束才能进行,而新的事务必须等待转储操作结束才能执行,因此会降低数据库的可用性。动态转储是指转储操作与用户事务并发进行,转储期间允许数据库进行存取和修改操作,它不必等待所有运行的事务结束,也不会影响新事务的运行,但是无法保证副本中的数据正确、有效、完整。所以在动态转储期间,往往会建立日志文件。后备文件加上日志文件就可以把数据库恢复到正确的状态。

1. Oracle数据库
(1) 两种归档模式(archive mode)
Oracle有两中归档模式:NO ARCHIVELOG和ARCHIVELOG。在NO ARCHIVELOG模式(该模式为缺省模式)下的数据库操作不归档在线日志重做文件。当存储介质损坏时,NO ARCHIVELOG模式的数据库只能恢复到上一次的备份点上。ARCHIVELOG模式的数据库可以通过上一次的备份和归档日志重做文件相结合的方式,恢复到介质损坏之前的点上。
以NO ARCHIVELOG模式创建的Oracle数据库可以切换至ARCHIVELOG模式。
(2) 多种备份与恢复方式
Oracle中的数据备份和恢复方式包括:脱机备份与恢复、逻辑备份与恢复、热备份与恢复。
* 脱机备份与恢复:脱机备份是一种静态转储技术,备份在数据库关闭、不工作的状态下进行。脱机备份包括两种实现方式:第一种是使用Oracle提供的工具Backup/Recover;第二种是利用操作系统的复制功能,复制数据文件,即:冷备份。
* 逻辑备份与恢复:逻辑备份与恢复是指将数据库、用户和表等对象的内容整个转出到一个二进制文件,然后在需要的时候通过转入恢复到原来的形式。这种方式可以备份整个数据库,指定用户和指定表的内容。
* 热备份与恢复:脱机备份和逻辑备份通常是用户不访问数据库时的静态备份操作。这些备份只保证数据备份前的一致性和完整性,不保证备份期间的数据一致性。为了保证数据的即时一致性,在备份数据的同时还需要备份日志文件。数据库运行在ARCHIVELOG方式下,同时作数据和日志文件的备份称为热备份。
(3) 实现步骤
选择使用何种备份方式,由具体的数据备份需求所决定。具体的Oracle数据库备份实现步骤需要参考Oracle相关文档,比如《Oracle8 Backup and Recovery Guide》。本实例采用Oracle中的逻辑备份,使用了exp和imp工具,以sde用户方式备份和恢复整体空间数据。
* 备份数据库:使用Oracle中的exp命令,以sde用户方式备份所有相关数据。
* 恢复数据库:使用Oracle中的imp命令,以sde用户方式恢复后备数据文件。
* 恢复ArcSDE系统文件:如果有必要,在恢复oracle数据之后,需要恢复安装ArcSDE的程序文件;另外还需要从备份机器上恢复dbtune,giomgr.defs,dbinit.sde,和services.sde文件。

2. SQLServer数据库
(1)备份和恢复方式
在MS SQL Server中,ArcSDE利用单独的用户数据库SDE(缺省名)来管理和组织空间数据。
SQLServer不仅可以在同一台服务器上备份和恢复数据库,还允许通过备份和恢复的方式在不同服务器之间很轻松地移动数据库。MS SQL Server也允许将一个服务器上的数据库备份恢复到另外一台服务器上。
如果要将数据库备份恢复到另外一台服务器上,两台服务器上的code page和排序方式必须相同。比如,不能把用二进制排序方式(Binary Sort Order,BSO)建立的数据库恢复到一个配置为缺省排序方式(字典顺序,dictionary)的服务器上。当然,可以通过在master数据库中运行'sp_helpsort'存储过程设定服务器的排序方式。
数据库的备份操作同时备份了数据库的系统表,包括sysusers。当在不同的服务器上执行备份和恢复操作时,备份数据库中所包含的用户可能会和新的服务器上master数据库中sysxlogins表中包含的用户不同。这样的话,就无法登录到恢复后的数据库,知道更正并统一master数据库中sysxlogins表和恢复数据库中sysusers表的登录映射。要使上述两个表同步,需要运行"sp_change_users_login"存储过程。
(2)实现步骤
* 备份SDE数据库到备份文件:既可以使用T-SQL中的BACKUP语句,也可以使用企业管理器中的备份工具向导来完成SDE和其他空间数据库的备份。
* 将备份文件复制到目标服务器
* 将备份文件恢复到目标服务器:可以使用企业管理器中的恢复还原工具向导来完成SDE和其他空间数据库的恢复。
* 统一SDE用户登录映射
A. 两个服务器上都有SDE用户,但是两者的SDE用户具有不同的标识
当恢复SDE数据库至新的服务器后,sde数据库中的sde用户的SID与master数据库中dbo.sysxlogins表中的sde登录名的SID不同,比如:
Use sde
go
Select SID from sysusers where name = 'sde'
Use master
go
select SID from sysxlogins where name = 'sde'

SID
-----------------------------------------------------------
0x76695419BFAED41184FD00C04F8D0451
(1 row(s) affected)

SID
-----------------------------------------------------------
0xEDDFCA8E56B0D411850000C04F8D0451
(1 row(s) affected)
此时必须统一两个表中sde用户的SID标识,运行"sp_change_users_login" 存储过程,示例如下:
    Use sde
go
sp_change_users_login 'update_one','sde','sde'
运行上述的SID查询来验证修改结果:
0xEDDFCA8E56B0D411850000C04F8D0451
0xEDDFCA8E56B0D411850000C04F8D0451
可以看出修改后两个表中sde用户的SID标识完全一致,此时就可以启动ArcSDE for SQLServer的服务来使用了。
B. 目标服务器上还没有SDE用户
这种情形是指目标服务器上还没有sde登录用户,此时执行上述的SID查询,结果如下:
Use sde
go
Select SID from sysusers where name = 'sde'
Use master
go
select SID from sysxlogins where name = 'sde'
SID
-----------------------------------------------------------
0x76695419BFAED41184FD00C04F8D0451
(1 row(s) affected)
SID
-----------------------------------------------------------
(0 row(s) affected)
要矫正这种情况,需要首先到目标服务器中添加sde登录用户,但是不要将sde数据库的权限授予sde用户。添加登录用户,使用"sp_addlogin"存储过程和在企业管理器中使用登录管理工具。比如:
sp_addlogin 'sde','go','sde'
然后需要运行 "sp_change_users_login" 存储过程来统一master内dbo.sysxlogins表和恢复后用户数据库内sysusers表中的sde用户SID标识。
use sde
go
sp_change_users_login 'update_one','sde','sde'
最后,可以执行SID查询来验证SID的一致性:
Use sde
Go
Select SID from sysusers where name = 'sde'
Use master
Go
select SID from sysxlogins where name = 'sde'
SID
-----------------------------------------------------------
0xF6DFCA8E56B0D411850000C04F8D0451
(1 row(s) affected)
SID
-----------------------------------------------------------
0xF6DFCA8E56B0D411850000C04F8D0451
(1 row(s) affected)
经过SDE用户的SID的统一之后,就可以启动ArcSDE服务或者使用直接连接(direct connection)方式使用恢复后的空间数据了。

posted @ 2006-11-28 20:13 Flyingis 阅读(2701) | 评论 (1)编辑 收藏

[DWR文档] WEB-INF 参考

     摘要: DWR中文文档--WEB-INF 参考

翻译的方式采用中英文对照,翻译的文字不会完全和英文一一对照,主要是为了在不失原意的情况下保证中文的阅读理解习惯,当然,翻译的过程需要大家的支持,翻译不妥的地方尽请拍砖、指正。  阅读全文

posted @ 2006-11-18 09:34 Flyingis 阅读(5277) | 评论 (0)编辑 收藏

DWR 中文文档

     摘要: 我是DWR初学者,虽然DWR入门简单,但还是想尝试翻译一下DWR的部分文档,翻译过程中自己会有更多的思考,翻译的方式采用中英文对照,翻译的文字不会完全和英文一一对照,主要是为了在不失原意的情况下保证中文的阅读理解习惯,当然,翻译的过程需要大家的支持,翻译不妥的地方尽请拍砖、指正。

Jet Mah已经开始翻译DWR文档,我将在他未翻译的文档中摘取比较重要的章节进行翻译,也算是对开源尽一点绵薄之力。我已翻译的部分在Java Tang中也会留言给出链接。  阅读全文

posted @ 2006-11-18 09:15 Flyingis 阅读(8328) | 评论 (2)编辑 收藏

中国计划建设自己的卫星导航系统

    2006年11月3日,中国在北京宣布计划建立一套自己的卫星导航系统,整个系统包含35颗卫星,并于2008年在亚洲区域投入运行。该系统名称为“Beidou”,将包括五颗对地静止轨道卫星和三十颗中距离地球轨道卫星,新华社通讯员11月2日。

    据报道,整个卫星导航系统将提供两套服务,其中免费服务面向大众,许可认证服务面向军事方面。面向商业客户的卫星系统服务将提供10米的定位精度,速度分辨率为0.2米/秒,而时间分辨率在50*十亿分之一秒以内。关于整套系统的费用没有详细的报道。

    在此之前,中国已经加入了欧空局35亿欧元伽利略计划研发卫星导航系统,以摆脱美国军用全球卫星导航系统的垄断。

    详细信息可以访问(英文):
    http://www.chinadaily.com.cn/china/2006-11/03/content_723687.htm

posted @ 2006-11-14 22:26 Flyingis 阅读(1316) | 评论 (2)编辑 收藏

用 JavaScript 玩转 DOM Level 1

     摘要: DOM(The Document Object Model)将HTML转换为XML文档格式来表达,为动态HTML编程提供了一种优雅的解决方案。DOM编程可以使用多种语言(Java中可以使用SAX进行XML编程),不论大家使用何种服务器端技术,JavaScript的DOM基础编程还是需要掌握的,最常见的莫过于getElementById(),引用Prototype.js使用最多的也是$(""),但是要做好Web客户端设计,我们需要了解更多更细。

当前各种主流浏览器对DOM Level 1标准支持的相对较好,我们就来看看在JavaScript中如何玩转DOM Level 1。  阅读全文

posted @ 2006-11-07 22:14 Flyingis 阅读(5337) | 评论 (6)编辑 收藏

[Design Pattern] The Decorator Pattern

     摘要: Decorator Pattern,看看魔兽中的山丘是怎么应用这种模式的(个人设想)。  阅读全文

posted @ 2006-11-07 11:04 Flyingis 阅读(3112) | 评论 (3)编辑 收藏

清除 Trojan [转载]

     摘要: 在网上找到的Trojan-Downloader.Win32.QQHelper.mo查杀过程,经验证方法有效,特转贴与大家分享。  阅读全文

posted @ 2006-10-24 16:38 Flyingis 阅读(1616) | 评论 (0)编辑 收藏

Firefox 2.0 正式提供下载,JavaScript 1.7 获得支持

    现在 Mozilla官方网站 还没有Firefox 2.0正式版的下载链接,但驱动之家已经开始提供下载链接,包括 Mozilla官方FTP ,和 mydrivers网站上本地下载 ,迫不及待的朋友可以立即开始体验Firefox 2.0。

    我用Firefox除了支持开源软件外,还有一个重要用途就是调试JavaScript,我之前的一篇随笔《
JavaScript 调试工具 》简单介绍了JavaScript的调试利器。随着Firefox 2.0正式发布,JavaScript 1.7也开始在最新版的Firefox中正式获得支持,虽然正式项目中还不大可能用到JavaScript 1.7,但做JavaScript开发的朋友肯定会给予JavaScript更多的关注。

    JavaScript 1.7在1.6的基础上加入了新的特性,具体大家可以参照这里:

    --
New in JavaScript 1.6 --

    --
New in JavaScript 1.7 --

posted @ 2006-10-24 14:57 Flyingis 阅读(1311) | 评论 (0)编辑 收藏

IE7 正式版推出

     摘要: IE7 官方正式版已经推出,看看它为我们带来了什么……  阅读全文

posted @ 2006-10-19 09:25 Flyingis 阅读(2770) | 评论 (7)编辑 收藏

[翻译] 如何在 JavaScript 中实现拖放(下)

     摘要: 终于完成了全文的翻译,由于时间比较参促,文章没有过多的校正与润色,阅读过程中难免会有些许生硬或不准确的感觉,请大家见量并指出,方便他人阅读。

原文作者将拖放功能的实现分步讲解,其核心的地方在于移动和放置元素时,鼠标、移动元素、目标元素关系的处理,只要这个问题处理好了,代码就很容易理解,译文仅供辅助参考之用,demo可以参考原文链接。  阅读全文

posted @ 2006-10-15 17:03 Flyingis 阅读(6644) | 评论 (19)编辑 收藏

[翻译] 如何在 JavaScript 中实现拖放(中)

     摘要: 上一篇文章介绍了移动页面元素所涉及到的捕获鼠标移动和鼠标点击的相关问题,本段文章将介绍如何移动和放置页面元素。  阅读全文

posted @ 2006-10-13 14:53 Flyingis 阅读(5283) | 评论 (2)编辑 收藏

[翻译] 如何在 JavaScript 中实现拖放(上)

     摘要: JavaScript擅长于修改页面中的DOM元素,但是我们使用JavaScript通常只是实现一些简单功能,例如实现图片的翻转,网页中的标签页,等等。这篇文章将向你展示如何在页面中,对创建的元素实现拖放。
(译者注:原文发布已有一段时间,但感觉作者思路清晰明了,值得一读。文章一次看完比较好,但时间有限,我会尽快将剩下部分补上)  阅读全文

posted @ 2006-10-11 16:20 Flyingis 阅读(7401) | 评论 (2)编辑 收藏

[Design Pattern] The Observer Pattern

     摘要: 在讨论设计模式时,我喜欢用英文名来称呼各种模式,觉得这样会更为准确一些。设计模式在Java开发领域已经是炙手可热的山芋,披上了这件战袍,似乎就可以在程序设计中立于不败之地,不仅可以规范自己的武功招式,还能够看清其他高手的武功套路。在接下来[Design Pattern]一系列的随笔中,我将系统的研究各种常用的设计模式,主要的参考资料是《Head First Design Patterns》,主要的思路是,介绍基本概念(虽然做Java开发的熟手已经对此熟悉的不得了),将思维转换为代码设计,谈谈在实际中开发的应用,也许还会有各种模式的弊端。  阅读全文

posted @ 2006-09-30 16:40 Flyingis 阅读(3007) | 评论 (1)编辑 收藏

GeoRSS 应用方案

    作者:Flyingis

    GeoRSS提供了一种地理位置搜索与聚合的方案,并且可以用于地理分析,例如在指定地点10公里范围内,所有可能受地震影响的地物的信息,在自己出行道路中出现交通事故的位置点,等等。只要RSS包含了地理位置信息,就可以将应用进行扩展。

    那么哪些技术方案可以支持GeoRSS呢?目前ESRI已经支持通过JavaScript API来使用GeoRSS,我们可以不用将GeoRSS导入到ArcWeb Explorer中,仅仅将GeoRSS URL链接输入到搜索框即可。如下图所示(图片来自于James Fee的博客)。


    遗憾的是,ESRI目前仅支持点的聚合查询,并且使用GeoRSS Feeds还存在一些bug。

    另外一种方案,就是结合Microsoft Virtual Earth API来使用GeoRSS,这是Virtual Earth API 3.0中新增的一项强大的功能。GeoRSS层可以很容易的使用基于WGS84 lat/long坐标系,或GeoRSS Simple语法的GeoRSS XML文件,加入一组点到地图上,具体的方法可以参考这两篇文章:

    http://blogs.msdn.com/keithkin/archive/2006/09/19/761333.aspx
    http://blogs.msdn.com/keithkin/archive/2006/09/19/761573.aspx

    在Keith的demo中,他实现了将鼠标停留在地图上某标注点,其相关信息就会反应出来,示例如下:

    http://krkinnan.members.winisp.net/samples/georss/hurricaneivan.html

    关于GeoRSS:http://www.blogjava.net/flyingis/archive/2006/09/25/71823.html

posted @ 2006-09-28 11:15 Flyingis 阅读(1975) | 评论 (0)编辑 收藏

GeoRSS

    作者:Flyingis

    RSS已经成为互联网上共享知识、分享信息的最为主要手段之一,通过订阅RSS,我们可以从网络的海量信息中获取我们所关心的数据,包括文字、图片等。将地址信息通过一种交互的方式,使得应用可以请求、聚合、分享、发布Feeds,成为地理信息在未来一段时间的一个热点。

    GeoRSS成为了地理信息数据Feed资源化的先锋队员,GeoRSS存在两种编码方式,分别是GeoRSS GML和GeoRSS Simple。前者是标准的GML应用,相比后者支持更为广泛的特性,可以和Atom 1.0、RSS 2.0、RSS 1.0一起使用,并且它还可以在非RSS XML编码的环境中使用。GeoRSS Simple显得更为轻便,当然在扩展性能上就会有所限制。

    举个例子说明这两者的区别,例如我们需要将一个点进行XML编码,使用GML和Simple两种方式的格式分别如下:

    Simple
<georss:point>45.256 -71.92</georss:point>

    GML
<georss:where>
  
<gml:Point>
    
<gml:pos>45.256 -71.92</gml:pos>
  
</gml:Point>
</georss:where>

    具体的介绍,可以参考GeoRSS官方网站:http://www.georss.org/。有时间我会对GeoRSS模型与使用方法进行分析。

posted @ 2006-09-25 20:58 Flyingis 阅读(2565) | 评论 (0)编辑 收藏

Firefox 2.0 rc1

    Mozilla Firefox 2.0 rc1已经可以下载测试了,它包含了许多新的变化,具体的参考这篇文章:
http://tech.cybernetnews.com/2006/09/12/another-round-of-theme-updates-for-firefox-2/

    从这个链接可以下载到最新的版本:
http://ftp.mozilla.org/pub/mozilla.org/firefox/nightly/2.0rc1-candidates/rc1/ 

    据Jithen Singh介绍,Mozilla Firefox 2.0 rc1对
ArcGIS Server 9.2 rc1似乎提供了更好的支持。

    更新:刚在mydrivers.com上面看到了一篇文章:《IE7 RC1 VS Firefox2 RC1》。比较有意思的对比测试。(2006-9-29)

posted @ 2006-09-25 09:25 Flyingis 阅读(1172) | 评论 (1)编辑 收藏

JavaScript 随笔汇集

     摘要: 更新日期:2006-11-18  阅读全文

posted @ 2006-09-18 15:31 Flyingis 阅读(4068) | 评论 (9)编辑 收藏

[翻译] "this" of JavaScript

     摘要: this是JavaScript中功能最强大的关键字之一。不幸的是,如果你不知道它具体怎么工作,你将很难正确使用它。原文的题目是《The this keyword》。
翻译不恰当的地方请大家指出。  阅读全文

posted @ 2006-09-15 15:02 Flyingis 阅读(3514) | 评论 (3)编辑 收藏

JavaScript 对象的反射及应用

     摘要: Java和.NET都有着比较完善的反射机制,用来处理未知的对象并获取它们的属性和方法。JavaScript虽然没有完善的反射体系,但在编程的时候还是可以通过代码设计来实现类似反射的基本功能。  阅读全文

posted @ 2006-09-12 18:50 Flyingis 阅读(5838) | 评论 (5)编辑 收藏

使用 JSON 创建对象

    作者:Flyingis

    一般在JavaScript中可以调用Object类的构造函数来创建对象:

var obj = new Object();

    并且可以将对象附加到其他对象上,类似于C++中的对象数组,例如,某大学里拥有多个专业,每个专业都有一位主任和多名讲师组成,在JavaScript中可以这样来描述:

var university = new Object();
university.specialty 
= new Array();
university.specialty[
0= new Object();

//该专业的主任是Sam
university.specialty[0].director.name = "Sam";
university.specialty[
0].director.age = 40;

//该专业的两位讲师分别是Tom和Jerry
university.specialty[0].instructor = new Array();

var tom = new Object();
tom.name 
= "Tom";
tom.age 
= 32;
university.specialty[
0].instructor[0= tom;

var jerry = new Object();
jerry.name 
= "Jerry";
jerry.age 
= "35";
university.specialty[
0].instructor[1= jerry;

    可以看出,当对主任和讲师有更详细的描述时,这样一层层的代码给人感觉非常繁琐,许多代码都是重复编写,不但增加了代码量,并且还很枯燥。

    JSON是一种轻量级的数据交换格式,它的优点就是便于读写,可以将JavaScript中的对象及其赋值写成键值对的形式,例如上面代码通过JSON来描述可以写成:

var university = {
  specialty : [
  
{
    director : [
      name : 
"Sam",
      age : 
40
    ],
    instructor : [
      
{name : "Tom", age : 32}
      
{name : "Jerry", age : 35}
    ]
  }

  ]
}

    这样来描述整个对象的内部结构显得更为简洁、清晰,除了声明属性和对象外,还可以使用JSON创建的对象定义成员函数。当然,不论采用何种方法来描述,目的都是为了更高效直观的编写JavaScript代码,我们可以使用JSON定义一个对象,然后使用JavaScript添加属性,也可以使用JSON来扩展JavaScript所定义的对象,创建任意复杂的对象层次。

posted @ 2006-09-11 19:33 Flyingis 阅读(3915) | 评论 (1)编辑 收藏

博客显示的问题(BlogJava 系统 bug)

    我的博客里全是江南白衣的随笔。

    今天已经是第二次出现这种情况,进入我的博客随笔全部重复为江南白衣的一篇随笔,但博客上面的标题和右边的日期、公告、链接、回复等等都还是我自己的,今天上午11:32出现第一次的时候感觉是缓存的问题,偶尔一次没怎么在意,现在下午14:30又出现了一次,dudu看看有没有问题。

    出现问题时的截图:http://www.blogjava.net/images/blogjava_net/flyingis/question2.gif

posted @ 2006-09-05 14:47 Flyingis 阅读(1036) | 评论 (2)编辑 收藏

BlueViewer 地图加载分析(C#)

     摘要: BlueViewer是基于.NET Link进行ArcIMS二次开发的一个实例,里面包含了WebGIS最基本的一些功能。全文对BlueViewer程序启动地图加载的整个过程进行了分析,可以作为.NET Link初学参考。  阅读全文

posted @ 2006-09-03 23:14 Flyingis 阅读(2697) | 评论 (5)编辑 收藏

关于 BOM

    作者:Flyingis

    BOM全称是Browser Object Model,在不依赖于网页内容的情况下提供和浏览器视窗交互的对象,下图显示了BOM的组成结构。

BOM-Structure.gif


    可以看出,window是BOM的核心对象,在使用window中所有对象时,可以省去window,例如window.document可以写成document,window.frames[0]可以写成frame[0]。为了对视窗进行操作,BOM提供了四种方法:moveBy(dx,dy)、moveTo(x,y)、resizeBy(dw,dh)、resizeTo(w,h),这四种方法比较简单,具体使用可以参考相关资料。

    BOM中没有特别复杂的概念,但需要注意的是,现在BOM还没有一个统一的标准,各种浏览器对BOM的支持程度也不一,相同的功能也许其对象描述并不相同,即使是BOM结构本身也存在问题,如location既存在于window下的第二级结构中,也存在于window.document下的第三级结构中,但它们的功能描述是相同的。在目前情况下,只有针对用户所使用的浏览器来定制代码,或为不同的浏览器分别进行代码描述。

posted @ 2006-09-01 17:22 Flyingis 阅读(1890) | 评论 (0)编辑 收藏

SVG 中使用 JavaScript

    作者:Flyingis

    SVG(Scalable Vector Graphics)是一种基于XML的语言,用来在Web中绘制矢量图形。当前,除了Mozilla 2.0外,没有一款浏览器在本质上支持SVG,都需要插件来显示SVG图形,著名的有Adobe公司和Corel公司的SVG插件。

    一个简单的SVG

<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink=http://www.w3.org/1999/xlink width="100%" height="100%">
<desc>
显示一个正方形和一个圆形
</desc>
<defs>
<rect id="myrect" width="150" height="150" fill="red" x="15" y="15" stroke="black"/>
<circle id="mycircle" r="75" fill="white" stroke="black" cx="150" cy="150"/>
</defs>
<use xlink:href="#myrect" />
<use xlink:href="#mycircle" />
</svg>

    为了更好的理解SVG中的标签,可以和HTML标签作个简单的比较,SVG中的<svg/>和HTML中的<html/>类似,<desc/>和<title/>类似,<g/>和<div/>类似。

    在SVG中可以使用JavaScript,当需要遵循一些规则:必须使用type属性;language属性是非法的;使用特殊XML字符时可以使用CDATA(SVG和CDATA都遵循XML规范);xlink:href替换src。

<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink=http://www.w3.org/1999/xlink width="100%" height="100%">
<desc>
显示一个正方形和一个圆形
</desc>
<![CDATA[
  function comp(a, b) {
    if (a > b)
      alert("a is bigger than b");
    else
      alert("a is not bigger than b");
  }
]]>
<defs>
<rect id="myrect" width="150" height="150" fill="red" x="15" y="15" stroke="black"/>
<circle id="mycircle" r="75" fill="white" stroke="black" cx="150" cy="150"/>
</defs>
<use xlink:href="#myrect" />
<use xlink:href="#mycircle" />
</svg>

    在SVG中使用JavaScript可以写在如下几个位置:<desc/>标签之后;在<defs/>中;在<g/>标签之前。

posted @ 2006-08-31 20:06 Flyingis 阅读(4031) | 评论 (0)编辑 收藏

浏览器中的 JavaScript

    作者:Flyingis

    之前写过不少JavaScript基础的随笔,基本上都是针对其语法、语言结构来论述的。但是,现在使用JavaScript最多的地方是在浏览器中,这里就简单谈谈浏览器中使用JavaScript。

    在浏览器中使用JavaScript分为内联和外联两种方法,和CSS比较相似。

    内联

<html>
<head>
<title>内联</title>
<script language="JavaScript">
  
function message() {
    alert(
"Good Day !");
  }

</script>
</head>
<body></body>
</html>

    外联

<html>
<head>
<title>外联</title>
<script language="JavaScript" src="../path/external.js"></script>
</head>
<body></body>
</html>

    在external.js中,可以包含任何js代码,例如类的定义、方法函数等。相比之下,使用外联方法引用js文件可以做到更安全、代码更容易管理、节省资源开销。之所以能节省资源开销,是因为当两个页面同时使用一个js文件时,该js文件只会被下载一次,避免的相同代码重复下载增加页面的代码量。

    网页中的JavaScript源代码一般放置在<head></head>区域,当写在<body></body>中时,一旦页面加载就会执行body中的JavaScript代码,无法人工控制代码的执行。如果需要页面加载时同时执行JavaScript方法,则需要在head中定义该方法,否则系统会报错。

    JavaScript最初只有一种浏览器的支持,因此,需要一种方法将JavaScript代码隐藏在老的浏览器中,避免对JavaScript解析产生错误,这就是我们过去经常可以看到的,在代码前后加上<!--><//-->,在现在看来,这种方法已经没有必要了,一是因为使用外联方式引用JavaScript代码更加合适,二是当前主流浏览器对JavaScript的支持已经越来越多,当然也就能正确识别JavaScript代码。

    在浏览网页时,当某张图片无法显示时,可以通过文字来替换它,当网页不支持某段JavaScript代码时,我们也能通过一种替代的方式来提醒用户自己的浏览器不支持JavaScript或禁止了JavaScript,即使用<noscript></noscript>,放置在body区域中。

    随着XHTML(eXtensible HTML)标准的出现,<script>标签也出现了一些变化,过去我看到有的页面在<script>标签中使用languange属性,有的使用type属性,当时没怎么注意,其实后者正是XHTML出现后所定义的,可以为JavaScript设置mime类型为"text/javascript"。

    XHTML带来的另外一个变化就是使用CDATA,使用CDATA可以在表达式中使用一些特殊字符,增强代码的可读性,避免使用"&lt"、"&gt"来分别表示小于和大于。

<script type="text/javascript">
<![CDATA[
  
function comp(a, b) {
    
if (a > b)
      alert(
"a is bigger than b");
    
else
      alert(
"a is not bigger than b");
  }

]]
>
</script>

    代码中大于和引号均使用了我们常见的书写形式,避免了使用XML实体所带来的阅读上的困难。当然,这也存在旧的浏览器无法识别CDATA的问题,需要我们加入注释来隐藏CDATA标签。大家可以想到,最好的办法还是使用外联的方法使用JavaScript。

<script type="text/javascript">
//<![CDATA[
  function comp(a, b) {
    
if (a > b)
      alert(
"a is bigger than b");
    
else
      alert(
"a is not bigger than b");
  }

//]]>
</script>

    虽然部分浏览器还不完全支持XHTML,但我们应该尽量按照XHTML标准来书写代码,使得该标准能够获得更大更广泛的支持。

posted @ 2006-08-31 20:01 Flyingis 阅读(2730) | 评论 (0)编辑 收藏

正则表达式--简单模式

    作者:Flyingis

    正则表达式除了用来匹配一些特殊字符外,还有许多其他的作用。Metacharacters,character classes和quantifiers都是正则表达式语法中的重要组成部分,可以用来实现更强大的功能。 

    Metacharacters

    正则表达式的Metacharacters主要包括:

    ([{\^$|)?*+.

    当需要使用这些符号的时候,需要在前面加上一个反斜杠"\",例如:

var reg = /\?/;
var reg = new RegExp("\\?");

    一个字符的表示可以使用它的文字符号,也可以使用ASCII码或Unicode码来代码它。例如,当一个字符使用ASCII码表示的时候,我们需要在一个两位十六进制的编码前加上"\x"。

var name = "apple";
var regName = /\x61/;
alert(regName.test(name));  
//输出"true"

    当然,使用十进制来表示字母a。

var reg = /\141/;

    使用Unicode来表示一个字符,需要四位十六进制的编码,例如\u0062代表b。

var s = "big";
var reg = /\u0062/;
alert(reg.test(s));  
//输出为"true"

    下面一段代码可以到达同样的效果:

var s = "big";
var reg = new RegExp("\\u0062");
alert(reg.test(s));  
//输出为"true"

    另外,有一些预定义好的特殊字符,用来表示特殊的含义。如:“\t,\n,\r,\f,\a,\e,\cX,\b,\v,\0”。

//将用户输入的新一行的所有字符都删除
var str = strWithNewLines.replace(/\n/g, "");

    Character classes
 
    Character classer代表着需要匹配的一组字符,将需要匹配的字符放在一对中括号里,正则表达式将能有效的识别第一个字符,第二个字符,等等。

    Simple classes

    如果需要同时匹配"pig"和"big",可以使用simple character class来实现:

var str = "pig, big";
var reg = /[pb]ig/gi;
var arr = str.match(reg);

    此时,arr中的数据包括"pig"和"big"。当然,使用ASCII或Unicode来表示p或b同样可行。

    Negation classes

    有时我们需要匹配除了少数几个字符外的所有字符,在这种情况下,我们可以使用negation class来进行匹配。例如,匹配除了a和b之外所有的字符,可以表示为[^ab]。在上一个例子中,将reg表示为/[^p]ig/gi,则结果中将过滤掉pig。

    Range classes

    顾名思义,range class就是用来指定某个范围的匹配字符,例如从a到z可以表示为[a-z],从1到10可以表示为[1-10]。如果将range class指定的字符排除在外,可以使用[^1-10],表示除了1到10范围外的所有字符。

    Combination classes

    举一个例子就清楚了,现在需要匹配从1到10,从a到g,并且加上新一行的所有字符,可以表示为[1-10a-g\n]。注意,在[]里不允许再嵌套[]
  
    Predefined classes

    因为有许多样式都不停在重复使用,因此一组预定义好的character classes可以用来简化一些比较复杂的类型。具体的可以参考相关资料,下面举个简单的例子:
  
var str = "8743 apple";
var reg = /[0-9][0-9][0-9]/;
alert(reg.test(str));  
//输出为"true"
  
    使用predefined class可以写成:

var str = "8743 apple";
var reg = /\d\d\d/;
alert(reg.test(str));  
//输出为"true"

    Quantifiers
 
    Quantifiers能够指定某种匹配方式需要进行多少次,包括指定确定的次数,或不确定的次数如至少多少次。

    Simple quantifiers

    下面列表中,指定了某种模式需要重复进行的次数,部分符号和闭包的意义一样:

simple quantifiers.gif

    例如var reg = /b?read/就可以表示bread或read。
  
    三种正则表达式的quantifiers

    Greedy quantifier: 对一个目标串进行匹配搜索,当在目标串中没有相匹配的字符串时,就删去目标串的最后一个字符,再次进行匹配,如果没有发现则再删去最后一个字符,依此类推,最后的结果要么已经将字符匹配上,要么目标串已经为空。

    Reluctant quantifier: 和greedy quantifier搜索风格相反。Reluctant quantifier从目标串的第一个字符开始对目标串进行搜索,当没有匹配时,给目标串加上一个字符,再次进行搜索,依此类推,直到在目标串上匹配成功,或整个目标串都被搜索但仍然没有完成匹配。

    Possessive quantifier: 直接对整个目标串进行匹配,要么匹配上,要么匹配失败,它只进行一次匹配。

    那么如何判断这三种不同的quantifiers呢?主要就是根据问号(?)星号(*)和加号(+)的组合来判断的,如下表所示。

three quantifiers.gif

    需要注意的是,possessive quantifier在目前主流的浏览器中都不被支持,IE和Opera在碰到possessive quantifier时将会抛出异常,Mozilla虽然不会发生错误,但会将它作为greedy quantifier来对待。


    相关链接:正则表达式--JavaScript 实现基础

posted @ 2006-08-11 16:09 Flyingis 阅读(3162) | 评论 (0)编辑 收藏

组装电脑与品牌机

     摘要: 最近开始在.NET平台下进行工作,Visual Studio 2005的高效、易用及强大的功能都给我留下了深刻的印象,但在VS2005下进行一些基础操作的时候,感觉自己好像在做工业设计,有时自己就会想,面对Java 和.NET,就好像是到电脑城去购买电脑一样,是选择DIY,还是选择品牌整机?不管怎样,充分利用已有平台进行深层次开发,把握对架构的理解,就显得更为重要。  阅读全文

posted @ 2006-08-11 09:16 Flyingis 阅读(2543) | 评论 (9)编辑 收藏

正则表达式--JavaScript 实现基础

    作者:Flyingis

    正则表达式用来从某一段字符串中匹配所需要的字符,这些字符可以非常简单,也可以非常复杂。JavaScript生来就对正则表达式有着良好的支持,在网络的字符搜索匹配中发挥着重要的作用。

    JavaScript通过RegExp类来支持正则表达式,举一个最简单的例子:
  
var regApple = new RegExp("apple");

    它可以匹配一个字符串中出现的第一个"apple"字符串,并且对大小写敏感。在构造方法中加入第二个参数"g"则代表的搜索出字符串中所有的"apple",这里"g"代表"global"。如果第二个参数为"i",则代表着case-insensitive,匹配过程中将不考虑字母的大小写。将上述两者综合起来,可以搜索出所有"apple"字符串,并且不考虑大小写问题。

var regApple = new RegExp("apple""gi"); 

    正则表达式有着并不唯一的表示方法,使用Perl语言中的语法,可以将上述表达式表示为:

var regApple = /apple/gi;

    创建了一个RegExp对象后,RegExp的方法可以构造出不同的匹配方式,因为正则表达式是对字符串进行的操作,所以String的一些方法在构造正则表达式的过程中也扮演着重要角色。

    RegExp对象的方法 

var sampleString = "Greenapple";
var regApple = /apple/;
alert(regApple.test(sampleString));

    上面代码输出的结果是"true",因为sampleString中包含了需要匹配的字符串"apple",这是最简单的检测方式。有时,我们需要知道匹配的详细结果,例如:

var sampleString = "green apples, red apples";
var regApple = /apple/g;
var arr = regApple.exec(sampleString);

    通过使用exec()方法,返回的arr是关于匹配结果的一个数组,包括每一个匹配的值及其所在的段,例如上例中是"green apples"还是"red apples"。match()方法有着和exec()相同的功能,只是表达方式不同:

var sampleString = "green apples, red apples";
var regApple = /apple/g;
var arr = sampleString.match(regApple);

    search()方法和indexOf()比较类似,返回第一个匹配的字符串所在的位置:

var sampleString = "green apples, red apples";
var regApple = /apple/gi;
alert(sampleString.search(regApple));  
//输出"6"

    String的方法

    String的replace()方法可以将指定的字符串替换为另一个字符串:

var sampleString = "There is a green apple.";
alert(sampleString.replace(
"green""red"));  //输出"There is a red apple."

    将replace()的第一个参数替换为一个正则表达式,可以达到同样的效果:

var sampleString = "There is a green apple.";
var regApple = /green/;
alert(sampleString.replace(regApple, 
"red"));  //输出"There is a red apple."

    replace()的第二个参数可以替换为一个function(),该function()接受一个匹配字符串作为参数,返回一个替换字符串。(存在疑问)

    使用正则表达式可以实现String的split()方法相同的功能。

var fruit = "apple,pear,lemon";
var arr = fruit.split(",");

    使用正则表达式:

var fruit = "apple,pear,lemon";
var reg = /\,/;
var arr = fruit.split(reg);

    以上这些都是JavaScript正则表达式最基本的一些特性,实现了一些最基本的功能,这些都不是正则表达式真正的强大之处,在作者接下来的随笔中会继续介绍。

posted @ 2006-08-10 21:04 Flyingis 阅读(5605) | 评论 (3)编辑 收藏

ArcIMS 连接器--.NET Link 使用方法

     摘要: ArcIMS各种connector的开发方式存在着一些区别,其中.NET Link连接器仅仅是对XML文件的一种搭配与组装,使用.NET Framework中对XML文件的操纵来拼装所需的ArcXML请求,并接受ArcIMS应用服务器的响应。文章附加了一个简单例子描述了整个过程。

使用.NET Link进行ArcIMS二次开发,开发人员不仅需要熟悉ArcXML_reference,还需要熟悉javascript客户端开发,因为用户在客户端进行的操作和地图服务的响应,均是由javascript脚本来完成的。  阅读全文

posted @ 2006-07-30 21:16 Flyingis 阅读(6352) | 评论 (70)编辑 收藏

ArcGIS-ArcSDE-ArcIMS 9.1 sp2 更新

    7月13日美国ESRI公司一口气放出了ArcGIS、ArcSDE和ArcIMS 9.1版本的Service Pack 2升级包,使用9.1版本的用户可以下载更新。

    ArcGIS 9.l Service Pack 2
   
http://support.esri.com/index.cfm?fa=downloads.patchesServicePacks.viewPatch&PID=43&MetaID=1162

    ArcSDE 9.1 Service Pack 2
   
http://support.esri.com/index.cfm?fa=downloads.patchesServicePacks.viewPatch&PID=19&MetaID=1163

    ArcIMS 9.1 Service Pack 2
   
http://support.esri.com/index.cfm?fa=downloads.patchesServicePacks.viewPatch&PID=16&MetaID=1164

    最近ESRI公司的核心开发人员一直忙于9.2系列产品的研发工作,这次释放出了三个9.1版本的产品的更新包,为9.1产品的用户解决了一些问题,可惜的是,.Net ADF一直都没有相应的更新,按照这个进度,很可能要等到9.2系列产品上市,.Net ADF作为其中之一才能获得bug的修复和功能的更新。

posted @ 2006-07-26 20:50 Flyingis 阅读(2058) | 评论 (2)编辑 收藏

FireFox 2 beta 1 支持 JavaScript 1.7

    Mozilla已经释放出Firefox 2 beta 1以供测试,在新增的众多功能特性中,支持最新的JavaScript 1.7是一个亮点,这使得Firefox成为了第一款支持最新JavaScript功能的浏览器。

    JavaScript 1.7中最值得关注的功能是提供了对iterator的支持,这使得在JavaScript中对数据进行迭代成为可能。使用Firefox 2 beta 1可以立即感受JavaScript 1.7所支持的新的功能。

posted @ 2006-07-25 13:59 Flyingis 阅读(1322) | 评论 (1)编辑 收藏

XMLHttpRequest 在 IE7 中将区分大小写

    一直以来本地XMLHttpRequest对象是不区分大小写的,但从IE7开始,XMLHttpRequest/ActiveX对象将对大小写敏感,这将和传统的面向对象语言例如Java、C#等保持一致,ECMAScript中也是如此

    过去在IE7版本之前使用的方法和函数不需要关心这个问题,但如果要将程序迁移到IE7中或保持所有浏览器版本的兼容性,需要对过去的程序进行修改来保证程序的正确运行。

    其实这种变化应该是发展的趋势,严格控制对象名称可以规范代码风格统一化并减少阅读代码所带来的困难,这是即使在对大小写没有任何要求的时候也应该注意的问题,能形成规约是件好事。

    IE7已经放出beta3版本,需要在Windows XP SP2操作系统下安装。

posted @ 2006-07-25 11:39 Flyingis 阅读(940) | 评论 (0)编辑 收藏

JavaScript 中的继承(下)

    作者:Flyingis

    Prototype

    在《JavaScript中的对象(下)》一文中,我们了解到任何prototype的属性和方法都会被传递到该类的所有实例中,利用这一特性,使用prototype也能实现继承。
 
function ClassA()  {
}


ClassA.prototype.id
= 1998;
ClassA.prototype.sayId
=function(){
   alert(
this.id);
}
;

functionClassB(){
}


ClassB.prototype
=newClassA();
ClassB.prototype.name
="";
ClassB.prototype.sayName
=function(){
   alert(
this.name);
}

    需要注意的是,这种实现继承的方法不能将参数传入到ClassA的构造器中,是一个缺陷。ClassB的所有属性和方法必需在将ClassB的prototype对象指向ClassA的实例之后进行附值。这样做是因为,prototype指向一个新的对象,在此之前prototype的属性和方法都被覆盖销毁。

    对代码进行测试:

var  obj1 = new ClassA();
var  obj2 = new ClassB();
obj1.id
= 1998;
obj2.id
= 2000;
obj2.name
="悉尼奥运会";
obj1.sayId();  
//输出"1998"
obj2.sayId();  //输出"1998"
obj2.sayName();  //输出"悉尼奥运会"

alert(obj2
instanceofClassA);  //输出"true"
alert(obj2 instanceofClassB);  //输出"true"

    在上述代码中可以看出,使用prototype实现继承,instanceof操作符出现了另外的用途,在用构造起定义类实现继承时,instanceof不会出现这种效果。但是使用prototype不能支持多重继承。
  
    在《JavaScript中的对象(下)》和上文的论述中可以了解到,使用构造器定义类实现继承和使用prototype实现继承均存在各自的缺陷,要避免出现这些情况,只有将两者混合使用。

    混合方法

    《JavaScript中的对象(下)》一文中曾经论述,创建一个类的最佳方法,是使用构造器的方法去定义属性,使用prototype定义方法。在继承中同样如此。

function ClassA(id) {
  
this .id = id;
}


ClassA.prototype.sayId
= function() {
   alert(
this.id);
}
;

function ClassB(id, name) {
   ClassA.call(
this, id);
  
this.name =name;
}


ClassB.prototype
=  new ClassA();
ClassB.prototype.sayName
=function(){
   alert(
this.name);
}

posted @ 2006-07-15 16:53 Flyingis 阅读(1550) | 评论 (0)编辑 收藏

JavaScript 中的继承(上)

    作者:Flyingis

    继承是面向对象语言基本特征之一,通过继承可以将父类所具有的特性遗传到子类。ECMAScript中的继承不像Java、C++等语言那么明显,直接通过关键字来实现,通常它是通过模拟方式来实现继承功能的,并且实现方式有多种。

    在继承中引入this关键字,使用构造器方法定义类来实现继承。一个构造器是一个函数,因此可以将父类的构造器作为子类的一个方法使用并进行调用。

function ClassA(id) {
  
this .id = id;
  
this .sayId = function() {
     alert(
this.id);
   }
;
}


function ClassB(id, name) {
  
this .newMethod = ClassA;
  
this .newMethod(id);
  
delete this.newMethod;

  
this.name= name;
  
this.sayName= function(){
     alert(
this.name);
   }
;
}

    注意,子类中所有新的属性和方法都必需在删除newMethod后引入,否则,可能存在用父类的属性和方法重写子类属性和方法的危险。另外,使用这种方法还可以实现多重继承,此时如果两个父类具有相同的属性或方法时,最后的类具有优先级。由于这种继承方法比较流行,ECMAScript第三版引入了两个Function对象:call()和apply()。

    call()

    call()方法是最接近上述继承方式的方法,它的第一个参数是this指向的对象,所有的其他参数都直接传到function。

function sayMessage(first, last) {
   alert(first
+ this.logic +last);
}
;

varobj =new Object();
obj.logic
= "or";

sayMessage.call(obj,
"Coffee ""Tea");  //输出"Coffee or Tea"

    用call()方法来实现继承,只需要this.newMethod相关的三行代码。

function ClassB(id, name) {
  
  //this.newMethod = ClassA;
  //this.newMethod(id);
  //delete this.newMethod;
  ClassA.call(this, id);  //this指向ClassB的对象

  
this.name =name;
  
this.sayName = function() {
     alert(
this.name);
   }
;
}

    apply()

    apply()方法需要两个参数:this所指向的对象,和传到function的由参数组成的array。

function sayMessage(first, last)  {
  alert(first 
+ this.logic +last);
}
;

var obj = new Object();
obj.logic 
= "or";

sayMessage.apply(obj, 
new Array("Coffee "" Tea"));  //输出"Coffee or Tea"
  
    同样,使用 apply() 实现继承可以通过如下方法实现。

function ClassB(id, name) {
  
//this.newMethod = ClassA;
  //this.newMethod(id);
  //delete this.newMethod;
  ClassA.apply(thisnew Array(id));  //this指向ClassB的对象

  
this.name = name;
  
this.sayName = function() {
    alert(
this.name);
  }
;
}

    当父类构造器的参数和子类构造器参数的顺序一致时,可以使用子类的arguments对象作为第二个参数。否则,必需创建一个array来传递参数,或是使用call()方法。

    文章待续……

posted @ 2006-07-15 10:38 Flyingis 阅读(1602) | 评论 (0)编辑 收藏

ArcIMS 体系结构

    作者:Flyingis

    ArcIMS可以运行在一个分布式环境中,包含客户端和服务器组件。一个完整服务的运行过程可以简单的描述为:一个客户端向服务器发送请求信息,服务器处理请求并返回信息到客户端,客户端将所获取的信息展现给终端用户。

architecture.gif

    ArcIMS空间服务器(ArcIMS Spatial Server)

    ArcIMS空间服务器是ArcIMS 的中心枢纽,承载着高负荷的计算任务,对地图数据的请求和相关信息进行处理。当接收到一个服务请求, ArcIMS空间服务器主要可以完成以下功能:

    Image—从在ArcIMS Author或ArcMap中创建的地图数据中创建影像文件
    Feature—缓冲地图特征数据
    Query—查找和搜索条件相匹配的特征数据
    Geocode—执行地址匹配操作
    Extract—从选择的地图特征数据中创建shapefile
    Metadata—打印出metadata 数据
    Route—在一系列的点之间计算路径距离

spatialserver.gif

    两个后台的进程支持着ArcIMS空间服务器的运行: ArcIMS Monitor和ArcIMS Tasker ,在Windows中它们作为后台服务运行,在Unix和Linux中作为daemon进程。

    ArcIMS Monitor跟踪ArcIMS空间服务器的状态。当系统重启时,ArcIMS Monitor将自动恢复ArcIMS服务。

    ArcIMS Tasker清除output目录中的文件。这些由空间服务器创建,以支持ArcIMS服务的文件,将在用户定义的时间间隔后被清除。当前服务为地图服务时,用户发送请求得到的数据均是由ArcIMS空间服务器对请求产生响应,返回的数据是图片,保存在output目录中, ArcIMS Tasker会在一定时间后清除这些图片数据。

ArcIMS应用服务器(ArcIMS Application Server)

    ArcIMS应用服务器控制着传入请求,跟踪当前哪些服务运行在哪些ArcIMS空间服务器中。ArcIMS应用服务器将请求传输到适合的空间服务器。应用服务器是一个Java应用程序,在Windows操作系统中作为一个Windows服务,在Unix和Linux中作为一个daemon进程。

ArcIMS应用服务连接器(ArcIMS application server connectors)

    ArcIMS应用服务连接器将Web服务器和ArcIMS应用服务器连接在一起。ArcIMS Servlet Connector是ArcIMS的默认连接器。它使用ArcXML在Web服务器和ArcIMS应用服务器之间传递信息。

    相对于ArcIMS Servlet Connector,还有几种其他的连接器可供选择:

    ColdFusion Connector
    ActiveX Connector
    ArcIMS Java Connector
    ArcIMS .NET Link

    ColdFusion和ActiveX连接器配合自定义的客户端工作,并且将自己的语言转换成ArcXML。ArcIMS Java Connector通过 JSP客户端或独立的Java应用程序和ArcIMS应用服务器保持通信。.NET Link提供TCP/IP或HTTP连接到应用服务器。

    关于连接器的相关资料,在 ArcIMS Help 中搜索主题:

    More about the ArcIMS Servlet Connector
    Connectors and ArcMap Server
    The ArcIMS documentation set
    ArcIMS Viewers

    当使用ArcIMS Designer创建了一个为用户提供地图内容的网站时,可以选择三种ArcIMS Viewers:HTML、 Java Standard、或Java Custom。通过定制这些Viewers或定制客户端可以达到基本相同的效果。另外,还可以使用比较成熟的客户端,如ArcMap、ArcExplorer和Metadata Explorer。

    从本质上说,viewer或客户端就是Internet GIS 应用或网络应用的网站,提供用户需要的地图服务。当用户访问这些网站的时候,他们可以在viewer中看到嵌入在网站中的定制地图。整个viewer决定了网站的外观和功能。

    相关viewer的相关资料,在ArcIMS Help中搜索主题:

    Choosing a viewer for your Web site
    Designing a Web site
    Overview of using the ArcIMS Viewers

    关于连接器、客户端的选择,可以参考
这篇文章

    ---- 参考资料:ArcIMS Help

posted @ 2006-07-09 11:50 Flyingis 阅读(9642) | 评论 (12)编辑 收藏

JavaScript 中的对象(下)

    作者:Flyingis

5  自定义类和对象

5.1  工厂方法

    在ECMAScript中创建工厂方法,返回一个特定类型的对象,以此实现代码的简洁适用。

function createFruit() {
  
var tempFruit = new Object;
  tempFruit.name 
= "apple";
  tempFruit.number 
= 5;
  tempFruit.showName 
= function() {
    alert(
this.name);
  }
;
return tempFruit;
}


var Fruit1 = creatFruit();
var Fruit2 = creatFruit();

    在createFruit()中可以加入形参来传入参数的值。随着ECMAScript不断被规范化,这种创建对象的方法已不再流行,一部分原因是语法上的,一部分原因是功能上的,如每个对象的实例都拥有属于自己的showName方法,给内存管理带来一定的开销。

5.2  构造函数

    选择一个类名,第一个字母大写,该类名即是构造函数的名称。创建一个构造函数和工厂方法比较类似,不同的是需要使用关键字new来创建对象的引用。使用构造函数的方式来创建对象和使用工厂方法有着相同的弊端。

function Fruit(name, number) {
  
this.name = name;
  
this.number = number;
  
this.showName = function() {
    alert(
this.name);
  }
;
}


var Fruit1 = new Fruit("apple"5);
var Fruit2 = new Fruit("pear"3);

5.3  使用 Prototype

    使用prototype属性可以用来创建新的对象,首先需要一个空的构造函数建立类的名称,然后所有的属性和方法都直接分配到prototype属性中。

function Fruit() {
}

Fruit.prototype.name 
= "apple";
Fruit.prototype.number 
= 5;
Fruit.prototype.showName 
= function() {
  alert(
this.name);
}
;

var fruit1 = new Fruit();
var fruit2 = new Fruit();

    但是,这样同样存在一些缺点。首先,构造函数中没有参数,给初始化带来一些麻烦,其次,当一个属性指向的是一个对象而非方法时,该对象会被所有的实例所共享,任何一点改动都会影响到其他对象引用的使用。

5.4  混合使用工厂方法和Prototype

这个概念很简单:使用构造函数定义所有除方法外的属性,使用 prototype 定义对象的方法。这样每个方法只会被创建一次,每个对象都能拥有自己对象实例的属性。

function Fruit(name, number) {
  
this.name = name;
  
this.number = number;
  
this.owner = new Array("Jerry""Terry");
}

Fruit.prototype.showName 
= function() {
  alert(
this.name);
}
;

var Fruit1 = new Fruit("apple"5);
var Fruit2 = new Fruit("pear"3);

5.5  动态 prototype

    简单来说,这种方法就是使用了一个标识符来判断 prototype 是否已经被指向某个方法,从而保证这些方法只会被创建并指向一次。

5.6  混合工厂方法

    这种方法和经典的工厂方法及构造函数方法在对象方法内存管理上存在同样的问题,一般不建议使用该方法,除了某些特殊情况(XML in JavaScript中有这样的例子)。

6  修改对象

    使用prototype对象可以对对象进行修改。除了用户自定义的对象外,ECMAScript原始对象也有prototype属性。直接使用 prototype可以给对象创建新的方法。

Number.prototype.toHexString = function() {
  
return this.toString(16);
}
;
var iNum = 10;
alert(iNum.toHexString());  
//输出A

    另外,使用prototype可以轻松修改已有的方法,让方法名指向新的方法。需要注意的是,指向新的方法后,原有的方法不再被任何对象使用,将会被垃圾回收器销毁,使得原有方法不再存在。比较安全的解决办法是,建立一个新的引用来保存原有的方法,然后再将原方法覆盖。

    比较特殊的是,ECMAScript中创建对象,在对象引用被创建后,可以给对象加入新的方法,并且可以立即在对象的引用中使用。这是ECMAScript的一个特性,但不推荐这样使用,以免带来不必要的麻烦,例如阅读理解、文档资料等。

posted @ 2006-07-03 14:02 Flyingis 阅读(3955) | 评论 (3)编辑 收藏

JavaScript 中的对象(上)

    作者:Flyingis

    面向对象语言需要具备三种基本特征:继承(Inheritance)、多态 (Polymorphism) 、封装(Encapsulation and Aggregation)。和Java 、C++ 等语言一样,ECMAScript 被认为是面向对象的,因为它同时支持这些特征。
 
var obj = new Object();

    该语句创建了一个对象,当构造函数没有参数时,可以省略后面的括号。我们通常是通过对象的引用来进行对象操作,当一个对象的引用为null时,ECMAScript将启动垃圾回收程序删除该对象,释放内存。当一个对象存在多个引用时,需要将所有的引用设置为null来释放该对象所占用的空间。

早期绑定和动态绑定

    早期绑定是指在对象被实例化之前对象的属性和方法已经被定义,使得编译器或解释器能够提前编译机器码。Java和VB支持这种特性,但ECMAScript 并非强类型,不支持早期绑定。

    动态绑定是指编译器或解释器在运行时才知道该对象的具体类型,之前并不会检查,只会判断这些属性和方法是否得到该对象的支持。ECMAScript对所有的变量使用动态绑定。

对象类型

2.1  原始对象

    ECMA-262 定义不受主机环境影响的ECMAScript支持的任意对象为原始对象,简而言之,原始对象就是ECMA-262定义的引用类型,比较常用的有Object、Function、String、Boolean、Number、Array、Date。 

    Array

   
Array有许多常用的方法,很多和Java类似,在此不作介绍。需要注意的是,使用push()和pop()两个方法,可以将Array看作一个栈,遵循后进先出规则(LIFO)。使用shift()和push()两个方法,Array对象即可看作是一个队列,遵循后进后出的规则(LILO)。splice()方法非常有用,它轻松的实现了链表的一些基本功能,如删除数据项、插入数据、替换数据。

    Date

   
ECMAScript中的Date类是基于Java早期版本中的java.util.Date类的,它可以精确表示1970年1月1日(格林威治时间)前后285616年的任意时间。Date是少有的几个重写了toString()和valueOf()方法,并且两个方法并不相同的类。valueOf()通常表示精确到毫秒级的时间,toString()通常返回个性化的时间表示方法,例如相同的时间在不同浏览器下显示的效果可能不一样。

2.2  Build-in对象

    Build-in 对象除了具备原始对象的基本特性外,它在 ECMAScript 程序开始运行时就可以使用,因此可以说任何 Build-in 对象就是原始对象。目前 ECMA-262 只定义了两个 Build-in 对象: Global 和 Math 。

    Global

   
在ECMAScript里,没有函数可以单独存在,所有的函数都必须是某个对象的方法。如isNan()、isFinite()、parseInt()、parseFloat()、encodeURI()、encodeURIComponent()、decodeURI()、decodeURIComponent() 等均是Global对象的方法,除此之外,Global对象还包括一些属性。

    Math

   
Math中有许多属性和方法可以用于数学计算,和Java中的比较类似。

2.3  Host 对象

    除了原始对象和Build-in对象外,其他对象均是Host对象。所有的BOM和DOM对象均被认为是Host对象。

类成员的访问方式

   
在面向对象语言程序设计中,常见的类成员访问方式有public、protected和private。在ECMAScript中,只有public一种访问方式,对象中所有的属性和方法都是可见的,因此,在程序设计时需要额外注意系统安全性的问题。在没有合理的程序规范之前,程序员在编写ECMAScript代码时,通常使用一定规范的命名方式来说明该属性或方法是私有的(仅仅是说明而已,实际上还是公有的),例如在名称前后加上下划线,或只在名称前加下划线。另外,在ECMAScript中没有static方法。

4  this
关键字

    this关键字是ECMAScript中一个非常重要的概念,通常在对象的方法中使用。

function whatFruit() {
  alert(
this.color);
}


var table1 = new Object;
table1.fruit 
= "apple";
table1.whatFruit 
= whatFruit;
var table2 = new Object;
table2.fruit 
= "pear";
table2.whatFruit 
= whatFruit;
table1.whatFruit();  
//输出apple
table2.whatFruit();  //输出pear

    当一个变量前面没有对象或this来引用时,ECMAScript认为该变量是一个本地的或全局变量,于是在本地和全局中去搜寻该变量,如果最后仍没有找到,将会在alert中输出null。

    文章待续……

posted @ 2006-06-30 15:20 Flyingis 阅读(2345) | 评论 (0)编辑 收藏

JavaScript 调试工具

    作者:Flyingis
 
    JavaScript代码看起来总是要比Java、C#乱的多,可能是自己还不熟悉JavaScript编程,因此一款优秀的JavaScript调试器就显得格外重要。目前在网络和书上见到最多的有:

    Microsoft Script Debugger: 集成在IE中的一款很原始的调试工具,具备基本的调试功能,除了可以用于调试客户端脚本,还能调试在Microsoft IIS上运行的服务器端脚本。该工具命令窗口是基于文本的,针对VBScript和IE环境进行调试会更加适用。
 
    Firefox JavaScript Console: 可以记录JavaScript中出现的所有警告和错误,诊断出大多数错误。工具比较简单实用。
 
    Venkman: 一个基于Mozilla的浏览器的JavaScript调试环境,是Mozilla浏览器的一个扩展。Venkman基于Mozilla JavaScript调试API(js/jsd),js/jsd API 构成了 Netscape JavaScript Debugger 1.1的基础,Netscape浏览器4.x系统都提供了这个调试工具。Venkman是目前比较流行的JavaScript调试工具。

    相关下载:

    http://www.hacksrus.com/~ginda/venkman/
    上面最新的版本是0.9.85,对于Firefox只能支持1.5以前的版本。

    https://dwr.dev.java.net/files/documents/2427/22010/venkman-0.9.85.jw2.xpi
    venkman-0.9.85.jw2.xpi是venkman-0.9.85xpi的修改版本,可以支持Firefox 1.5.0。 

    https://addons.mozilla.org/firefox/216/
    在Mozilla官方站点上,venkman有了另外的一个名称——JavaScript Debugger,已经发布了0.9.87版本,支持Firefox 0.9-3.0,Mozilla 1.0-1.8,Thunderbird 0.9-3.0的所有版本浏览器。
    除了官方网站外,该工具的扩展安装也可以通过链接
    http://www.blogjava.net/Files/flyingis/javascript_debugger-0.9.87.rar进行本地下载。
 
    另外有一些JavaScript专用IDE,有兴趣可以试用一下:
 
    Cardinal JavaScript IDE:
    http://home.earthlink.net/~mafriedman/ide/

    JavaScript IDE for Eclipse:
    http://www.basement.org/archives/2005/09/js_eclipse_javascript_ide for.html

    JavaScript IDE(共享软件):
    http://www.downloadjunction.com/product/software/42264/index.html

posted @ 2006-06-16 20:16 Flyingis 阅读(13278) | 评论 (3)编辑 收藏

ECMAScript 基础

     摘要: JavaScript三大核心之一ECMAScript语言快速入门基础。
目前已更新:ECMAScript语言基本特点;原始数据类型;数据转换;Type Casting;引用类型;操作符和语句;Functions……
最近更新日期:2006-6-16  阅读全文

posted @ 2006-06-13 15:36 Flyingis 阅读(3632) | 评论 (4)编辑 收藏

JavaScript 基本组成

    JavaScript的学习,以Nicholas C.Zakas的《Professional JavaScript for Web Developers》为基础材料。

    JavaScript作为一种网络客户端的脚本语言,由以下三部分组成:

1.  ECMAScript--JavaScript的核心,描述了语言的基本语法和对象。

    ECMAScript经历了三个版本的更新,现在大多数网络浏览器都支持Edition3。ECMAScript主要提供语言相关的信息与标准,如语法、类型、声明、关键字、保留字、操作运算符、对象等等。

2.  DOM--The Document Object Model,描述了作用于网页内容的方法和接口。

    DOM是HTML的一个应用程序接口,它也经历了三个版本的更新,其中以第一和第二个版本使用最为广泛,在第二个版本中,最重要的特性莫过于提供了事件响应的接口,处理CSS的接口,移动窗口的接口,并且能够控制代码树的结构等等。
    除了使用最多的DOM Core和DOM HTML标准接口外,其他的部分语言也拥有自己的DOM标准,如SVG、MathML、SMIL。

3.  BOM--The Browser Object Model,描述了和浏览器交互的方法和接口。

    例如弹出新的浏览器窗口,移动、改变和关闭浏览器窗口,提供详细的网络浏览器信息(navigator object),详细的页面信息(location object),详细的用户屏幕分辨率的信息(screen object),对cookies的支持等等。BOM作为JavaScript的一部分并没有相关标准的支持,每一个浏览器都有自己的实现,虽然有一些非事实的标准,但还是给开发者带来一定的麻烦。

posted @ 2006-06-11 11:37 Flyingis 阅读(3306) | 评论 (0)编辑 收藏

了解 Ajax 框架--充电开始

    作者:Flyingis
   
    这学期一直忙着找工作、毕业论文和毕业前的各种手续,学习速度放慢了不少,大多数时候只是上来看看。现在正式开始充电,补充新的知识,为了工作需要,首先从客户端技术Ajax开始。

    Ajax高手在Blogjava上有不少,还有众多潜水高手,在这里,随笔记录的仅仅是自己的学习轨迹,不足之处希望大伙能指出,和大家一起讨论,帮助我提高。“
工欲善其事,必先利其器”,首先总结一些Ajax常用的框架。

    Ajax框架有基于服务器端和客户端两种,多数是开源实现,并且发展速度很快。

    服务器端框架

    1.  Sajax
    Sajax拥有活跃的社区,支持Perl、Python、Ruby、ASP等语言,每种语言Sajax都有一个简单的库,利用Sajax可以直接从JavaScript调用服务器代码。
    官方网站:
http://www.modernmethod.com/sajax

    2.  JSON
    JSON作为JavaScript语言的一个子集,是一种描述数据的轻量级语法,和XML类似,用于交换数据。XML相关的有XML-RPC,JSON也有JSON-RPC远程调用协议,它在Java、Ruby、Python、Perl中都有实现。
    网上参考:http://www.crockford.com/json/ 。

    3.  DWR
    DWR这个字眼出现的频率较高,在网上搜索了一下,查到DWR全称是Direct Web Remoting,代表着可以直接从JavaScript远程调用Java方法。使用DWR需要一些额外的配置,如编辑Web应用的描述文件,编辑DWR的配置文件,来指定可以远程创建和调用的类,从这种方式可以看出其中存在一些安全隐患,但是,由于DWR支持常用的Struts/WebWork/Tapestry Web框架,在Apache协议下发布,加上丰富的文档资料,使得DWR在Java领域非常流行。
    介绍DWR的相关文章可以参考:
    http://www.blogjava.net/mstar/category/2359.html
    http://www.blogjava.net/zkjbeyond/category/11348.html
    更多信息可以访问:http://getahead.ltd.uk/dwr/index

    4.  Buffalo
    Buffalo是由国人开发的Ajax框架。Buffalo中定义了Web远程调用的传输基础,并且将远程调用对象完整的序列化到了本地,成为可以被JavaScript编程触及的对象。Buffalo中的重要组件-BuffaloBinding,提供了将JavaScript对象绑定到HTML元素的能力。这种绑定将是无侵入的,只需要在HTML元素中加入若干个不影响排版的属性,即可将数据与界面绑定。Buffalo1.2引入了新的众多的特性包括,新的重新改写的Spring集成,与流行JavaScript库Prototype的集成,支持浏览器前进后退按钮等等。
    下载链接:http://www.amowa.net/buffalo/ 。[引自CSDN]

    5.  Ajax.Net
    顾名思义,Ajax.Net是.Net平台下的Ajax框架,它可以从JavaScript客户端调用.Net方法。Ajax.Net所包括的DLL可以和VB.Net/C#配合使用,其相关文档也很多。参考网站:http://ajax.net/ 。

    6.  Atlas
    这是Microsoft的一个项目,其特点在于提供客户端脚本框架、ASP.Net控件及Web服务集成。微软的项目,还是值得关注的。
    相关介绍:http://blog.joycode.com/saucer/archive/2005/06/30/58284.aspx/ 。

    7.  Ruby on Rails
    这个就不用多说了,前段时间开始就炒的异常火热的一个框架,建立在Ruby语言基础上,其最显著的特性是能够快速开发Web应用,使用Rails会觉得Ajax非常简单。Rails拥有许多JavaScript库,另外有一个模块封装了Ruby的JavaScript调用。对各种Rails的介绍,可以参考江南白衣的文章各系Rails大点兵。网站参考:http://www.rubyonrails.org/

    客户端框架

    1.  Dojo
    最老的框架之一,2004年9月开始开发,它具有一个独特的特性,即支持向后和向前按钮,通过注册一个回调的方法,使得用户在点击向后和向前按钮的时候调用改方法,实现后退前进的功能。Dojo是相对成熟的工具包之一。
    具体内容参考网站:
http://dojotoolkit.org/

    2.  Rico
    Rico侧重点在于拖放效果、数据网格、自定义页面布局、淡入淡出等人性化效果的轻易实现,使用Rico需要Prototype.js库来支撑,
zkjbeyond有关于Prototype.js的基本介绍
    Rico官方网站:
http://openrico.org/home.page/

    3.  Flash/JavaScript集成库
    当我刚进入大学的时候,Flash技术和JavaScript特效都是当时网络中最流行的字眼,但Flash丰富的用户体验更让人印象深刻,小小系列以及雪村的网络MTV都是比较早的作品,还有众多Flash制作的网站。在现在Ajax流行的环境下,Flash的臃肿和需要安装插件机制使得它不再那么耀眼,但是如果要混合使用Flash和Ajax,则可以使用Flash/JavaScript集成库,这个工具集可以使得JavaScript和ActionScript(Flash中支持的语言)能够相互调用,传递数据。
    相关资料可以访问:
http://weblogs.macromedia.com/flashjavascript/

    4.  SACK
    SACK是一个针对XMLHttpRequest的瘦包装器,可以简化Ajax开发,它由一个JavaScript文件组成,包含很少的代码,入门比较方便,它最主要的特性应该就是足够简单。
    相关信息可以访问:
http://twilightuniverse.com/projects/sack/

    5.  RSLite
    RSLite是远程脚本的一个实现,从2000年开始发展。它的特性在于拥有广泛浏览器的支持(因为没有利用XMLHttpRequest对象),它是一个轻量级的框架。
    网站信息:
http://www.ashleyit.com/rs/rslite/

    6.  Google AJAXSTL
    Google AJAXSTL是使用XPath的XSL转换(XSLT)的JavaScript实现。该工具包很小,并且还不完善,但作为使用AJAX的先驱,还是应该给予一定的关注。
    开源链接:http://goog-ajaxslt.sourceforge.net/

    这些是个人最初所关注的一些框架,
ComputerboyAjax框架汇总Ajax Resources有更多的对Ajax框架及相关资源的介绍。

posted @ 2006-06-10 17:42 Flyingis 阅读(4684) | 评论 (0)编辑 收藏

学术与工作

    作者:Flyingis

    在校园里我已经度过了第二十四个年头,一直还没有机会踏入到社会中去经历工作的锻炼。在大学校园里六年,我感受的是学术的氛围,学习的是做学问的方法。只是在硕士期间参与导师的一个横向项目,让我第一次有机会在实际工程项目中施展拳脚,也亲身感受到了学术与项目工作之间的差异。

    做学术和实际工作有一些共同点,它们都需要有踏实认真的学习态度,都需要循序渐进不断积累,它们对参与者态度的要求是一致的。并且都需要有良好的合作团队来使得大家共同提高,事半功倍。但是它们又存在太多的不同,主要体现在以下几个方面:

    1. 学术上对理论强调的比较多,任何发表在高水平期刊上的论文,没有厚实的理论基础作为支撑根本不可能发表,即使是在Nature&Science上发表的原创性论文,也是“站在巨人的肩膀上”完成的,因此,做学术需要看大量的相关文献资料,在前人的基础上做研究。工作侧重的是实际工作经验,和完成工作的能力,在工作中,老板基本不会过问你采用什么技术来实现这一目标,他需要了解的是你能否达到他的目标,需要多长时间,预计完成的效果如何,能否满足客户要求等等,有时候碰到一个难点可能有多种方法来解决,当技术人员所具备的技术并不是最高效的方法,但也能解决问题,如果基本不影响结果往往会采用自己所熟悉的方法来完成,因为客户他们一般是不怎么太关心中间的技术细节的,但在学术中讲究的就是最好,要求的是突破前人的研究成果,否则你的成果只能说是一个应用,而不是创新。

    2. 做学术,在中国注重的还是发表的文章,期刊的质量越高越好,这种评判一个人学术水平的高低既合理,但又存在问题。合理体现在,一篇高质量或至少是自己精心研究完成的论文,代表的是自己研究的精华,垃圾论文不说,写一篇好的论文其实真的不是件容易的事情,特别是理学的学科,一篇短短的万字不到的论文,需要你阅读的可能是百万字的文献,以及对文献的思考,再加上自己在该领域的实际工作的提炼,文字、排版、制图、分析、投稿、修改,每个过程都不省事,在SCI特别是外文的SCI上发表一篇文章的确是自己的精心之作。但其中存在的问题,就是急功近利的人太多,不仅是在实际工作中,在学术上浮躁的人也太多太多,使得现在国内垃圾刊物靠论文赚钱,一般的核心期刊靠专辑来盈利,并靠有国家自然科学基金、985、973重大项目支撑的论文撑门面,减少了对学术本质的专注,使得学术领域也渐渐成为了中国最腐败的领域之一。做项目,注重的是最后的运行效果能否满足客户需要,中间的过程和技术框架只是项目完成报告中的例行公事,只要软件能够运行起来,并在功能、效率、安全、界面上都符合要求,用.net还是Java,用WebWork还是JSF其实都是次要的了,更不用去过多的考虑我采用的技术在理论上是否达到了国内领先、国际先进了,关键还是结果。工作中,当然也逃不掉浮躁之风,特别是政府的政绩工程项目,往往是烂掉不能用的。

    3. 做学术,从理论上说,在某些领域可能不需要太多的资金支持,当自己研究成果出来了就可以名利双收,这样的学者在国外可能更多一些。做项目工作,没有钱是肯定不行的,否则怎么能让这么多员工安家乐业,只有资金才能创造好的工作环境,才能吸引人才。

    前段时间忙自己的毕业论文,确实让我着急了几天,因为自己两年毕业时间比较仓促,论文的题目和自己先前做的项目又没有任何关系,只能从一个应用的角度,加上一些理论经验的支撑,完成了论文,硕士论文总共所花的时间是一个半月,真正紧张从早到晚忙论文的时间是半个月,自己不是贬低自己论文的水平,至少能够符合现在对硕士论文的要求,但我知道自己能做的更好,并且能好不少,如果我有一个更好的平台,自己所做的项目能支撑自己的论文。还好我完成了论文,我之前的项目经验也让我在找工作的时候没有碰到什么困难,但看着BlogJava上众多高手对技术的痴迷和丰富的工作经验,有时我在想我在学校里获得了什么,一点项目经验和一个学位证,但两者根本就是脱离的,在我们这批学生中,我还算是比较幸运的,那其他的人怎么办呢?因此才会出现现在企业招人难,但学生也过剩的问题,看到这两天BlogJava中也有
对企业招人的讨论 。一位博士对我说过,在硕士、博士阶段,如果学术上没有什么成就,你获得的就是交际层面的提高、扩大,还有一个学位证,同学资源的确是宝贵的,学位证,在中国有还是比没有好,他说的没错。

    当然,不是所有的毕业生都是能力差的,出色的也不少,可以这样说,只要是在大学里认真做过事情,学习过知识的人,找工作都不难。文中所说的,只是作者自身的一些感受。马上就要奔赴工作岗位了,从学术转到工作,对我来说应该问题不大,但自己已经开始感觉到压力,踏实工作是我现在唯一能想到的事情。

    忘了一件事,今天六一,这节日早已不属于我们,但祝愿博客园中已成为父母的程序员的宝宝们节日快乐,健康成长!

posted @ 2006-06-01 11:59 Flyingis 阅读(1351) | 评论 (6)编辑 收藏

一幅土地资产评价简图

    近段时间在忙毕业设计,研究程序开发设计的时候少了。
   
    传一张论文中用到的图示,遥感数据的解译、编辑、空间地理计算、成图在Erdas + ArcGIS中完成,计算的理论基础层次分析法(AHP)和Saaty提出的1~9比较标度法。图中省略了一些图层信息和基本元素。(点击标题进入可以看到图

土地资产价值分布图.jpg

posted @ 2006-05-23 10:02 Flyingis 阅读(894) | 评论 (0)编辑 收藏

GeoServer 1.3.1 beta 发布(重大更新)

地理信息系统服务器 GeoServer OpenGIS Web 服务器规范的 J2EE 实现,利用 GeoServer 可以方便的发布地图数据,允许用户对特征数据进行更新、删除、插入操作,通过 GeoServer 可以比较容易的在用户之间迅速共享空间地理信息。

GeoServer 主要特性包括:兼容 WMS WFS 特性;支持 PostGIS Shapefile ArcSDE Oracle VPF MySQL MapInfo ;支持上百种投影;能够将网络地图输出为 jpeg gif png SVG KML 等格式;能够运行在任何基于 J2EE/Servlet 容器之上;嵌入 MapBuilder 支持 AJAX 的地图客户端;除此之外还包括许多其他的特性

GeoServer 最新的版本 1.3.1 beta 增加了 GeoTools 2.2.x GeoTools 是一款基于 Java 的开源 GIS 工具集,允许用户对地理数据进行基本操作。通过 GeoTools 的各种接口和 helper 类,可以写入新的数据格式,通过 GeoTools GeoServer 提供的插件,在不进行重新编译的情况下,可以让 GeoServer 支持更多的数据格式,甚至只需要通过 GUI option 设置即可。

一直都比较关注 GeoServer GeoTools 的发展情况, GeoServer 提供了一个相对简易的地理信息服务系统, GeoTools 包含地理信息数据基本操作的源码实现,是学习地理信息基础研发和 WebGIS 的经典资料库,两者的合并和今后的发展无疑会吸引众多地理信息开发者的目光。
     


GeoServer 主页: http://docs.codehaus.org/display/GEOS/Home

GeoTools 主页: http://www.geotools.org/

GeoServer 1.3.1 beta 下载:

http://docs.codehaus.org/display/GEOS/2006/05/06/GeoServer+1.3.1+beta+release

posted @ 2006-05-14 11:13 Flyingis 阅读(3060) | 评论 (6)编辑 收藏

模型与地理建模

作者: Flyingis

模型是为了理解和预测现实世界而构建的一种有效的替代物,它不是现实世界的复制,它是物体的一种简化,并能够体现物体的关键特征。地理学研究的目的是理解人类与环境间的关系,在地理建模过程中必然包含了许多人为或主观因素,但也不能随心所欲去表达所要表达的世界。一个好的模型可以把一个复杂的问题简单明了地表达出来,反之则会将问题描述的非常复杂难懂。

建模的步骤一般分为:建立概念模型;建立定量模型;模型检验(模型验证、模型确认);模型应用。目前,由于地理问题的复杂性和不确定性,地理学的量化水平还比较低,其建模主要是借鉴地质学、生态学和水文学等相关学科的模型和建模方法来研究有关地理环境问题。

地理建模一般具有复杂性、空间性、时间性和模糊性特点。在地理学中,建模的对象是地理系统,它具有明确的时间和空间特征。地理建模包含两种含义:空间实体对象建模和地理问题建模。空间实体对象是地理特征的抽象与几何表示,它的建模是地理信息系统所关注的主要内容。地理问题建模则涉及到地理学的所有领域。

在地理建模中,地理信息系统提供了数据的支持、模型库的管理和建模结果的可视化,是地理建模重要的技术支持。地理信息系统侧重于空间数据的存储、管理和制图,分析方法基本以空间位置为核心,关注的是对象之间的空间位置关系。地理建模中,空间位置是作为数据的属性来考虑,研究各个要素之间的关系以及这种关系的表现形式。归纳起来,地理信息系统的主要研究内容是空间数据的管理、空间关系的分析和表示,地理建模研究的是地理要素之间关系的建立、解释和分析。

地理建模针对地理问题,使用系统分析方法、物理方法和数学方法建立模型,对模型进行分析,以便为政府或经济、社会发展的决策提供基础支持。地理建模应用的方法,不同于决策分析中应用的方法,决策分析主要涉及信息论和控制论的内容,如规划方法、投入产出方法等。

posted @ 2006-05-09 10:35 Flyingis 阅读(1388) | 评论 (1)编辑 收藏

网站项目管理(二)

     摘要: 网站项目管理中的团队氛围,项目文档,和其他要求。  阅读全文

posted @ 2006-04-25 23:09 Flyingis 阅读(2297) | 评论 (1)编辑 收藏

网站项目管理(一)

     摘要: 网站项目管理中的网站界面,项目进度,和人力资源。  阅读全文

posted @ 2006-04-25 11:14 Flyingis 阅读(2031) | 评论 (1)编辑 收藏

GIS 缓冲区应用及算法实现

作者: Flyingis

地理信息空间几何关系分析主要包括邻近度 (proximity) 分析、叠加分析、网络分析等。缓冲区分析是邻近度分析的一种,缓冲区是为了识别某一地理实体或空间物体对其周围地物的影响度而在其周围建立具有一定宽度的带状区域。缓冲区作为独立的数据层进行叠加分析,可应用到道路、河流、环境污染源、居民点、辐射源等的空间分析,为某种应用目的提供科学依据,另外,结合不同的专业模型,可以在生活、军事、城乡规划等领域发挥重要的作用。

针对点、线、面不同的几何类型,建立缓冲区的方式相互有所不同。建立点缓冲区比较简单,即以某点要素为圆心,以缓冲半径 R 作圆,得到点要素的缓冲区;线要素的缓冲区是以线为轴,以 R 为距离作两侧的平行线,在线的两端构建两个半圆弧段,和平行线一起组成缓冲区;面缓冲区的建立,是以面要素的边界为基线向内外侧作平行线,平行线和基线里的区域就是面缓冲区。除此之外,还可以对栅格数据建立缓冲区,根据不同的模型方程建立动态缓冲区,不论对什么样的数据建立缓冲区,其基本方法都是相似的。

缓冲区实现算法有矢量方法和栅格方法两种。其中矢量方法数据量小,方法相对成熟,栅格图像需要进行栅格像元之间进行布尔运算,当缓冲区较大时会带来较重的运算负荷,实际运用中存在一定的局限性。矢量方法算法一般遵循以下步骤:

:确定中心点——以中心点为圆心、 R 为半径生成一个圆——得到缓冲区边界

线、面 :确定轴线——以距离 R 生成中心轴线的平行曲线——处理转角弧段——对生成的弧段进行求交、合并运算——生成缓冲区边界

常用的矢量数据中心线扩张算法:

角分线法

基本思想:即“简单平行线法”,在轴线的两边作出平行线,在转角处形成尖角,两端形成弧段,组成缓冲区。

缺陷:难以保证在尖角处缓冲区左右边线等宽;校正过程复杂,主要体现在轴线折角很大和很小时的情况;算法模型复杂,主要是因为几何生成过程中需要处理较多的异常。

凸角圆弧法

基本思想:顾名思义,即是在转角外侧用圆弧来代替尖角,内侧仍然使用尖角的方法,生成缓冲区。

实施步骤:

1.        直线性判断,判断相邻三点是否在同一直线上;

2.        折点凸凹性判断,确定转角的地方哪侧使用直线求交,哪侧使用圆弧连接;

3.        凸点圆弧的嵌入,即将转角外侧形成的圆弧和两边的线段相连;

4.        边线关系的判别与处理,岛屿多边形参与缓冲区边界的构成,重叠多边形不参与缓冲区边界的构成;

5.        缓冲区边界的形成,具体是将重叠区域进行合并,绘制外围的边线,包括岛屿多边形的轮廓,形成最终的缓冲区边界。

在缓冲区算法中,需要注意的一个问题是缓冲区多边形的重叠与合并,包括同一要素缓冲区的重叠和多个要素之间缓冲区的重叠。栅格数据缓冲区内的栅格具有一个与其影响度对应的一个值,如果重叠区域具有相同影响度则任取一值,如果不同则采取影响度大的代替影响度小的方法处理。对于矢量数据的处理算法有三种:数学运算法;矢量-栅格转换法;矢量-栅格混合法。 

posted @ 2006-04-17 15:25 Flyingis 阅读(7688) | 评论 (9)编辑 收藏

地理网格


    作者:Flyingis

地理网格是将平面以某种规则分级的空间数据结构,具有较高的标准化程度,它有利于面向空间数据库和几何操作算法的研究和开发。使用地理网格可以将地理空间定位和地理特征描述关联起来,以网格单位作为基本分辨率,控制在允许的误差范围内。

最常见的地理网格是经线和纬线组成的网格系统,网格由等度数间隔的经线和纬线交叉组成,空间数据的属性与经纬网格内的点相关联,方便网格内空间数据的获取与处理。网格系统可以在原有较小分辨率网格的基础上创建更细的子网格,增大其分辨率。一个网格可以被分成 2 个子网格,最常见的网格结构即是n=2的四叉树网格结构。更普遍的,可以定义 nd 树结构的网格系统,其主要特性有:

1.        在空间数据库理论中,二维空间域便许存储在存储器的一个线性地址空间里,因此空间位置信息必须经过一定的转换才能存储在计算机中,使用 nd 树可以拓展线性空间的排序方法,便于计算机存储。

2.        创建分级的一维地址。如果较大范围的空间区域内某种属性值一致,则以较低分辨率的网格来表示,如果属性值经常变化,则用较高分辨率的网格来表示,这样可以节省存储空间。

因此,用地理网格来模拟地球曲面的时候,最为关键的问题是分辨率和网格。使用地理网格的目的就在于对空间格局的一种表达,并且提供简单有效的空间数据结构算法。在空间数据结构中,它既可以像栅格数据一样用最小单元格来表达空间区域对象,也可以像矢量数据一样用点代替传统的坐标点来表达空间实体的几何特征,这两种数据结构分别对应于存储区域信息的网格系统和存储位置信息的网格系统。

目前,建立全球地理网格模型还面临许多困难,这些困难主要来自于基于地理坐标系统的地理网格还存在一些缺陷,例如网格单元面积不等所带来的复杂性,网格的各种形式的变形,网格复杂的邻接特性,这些都给实际应用带来了困难。

参考资料:
GIS空间分析原理与方法
 

posted @ 2006-04-13 23:19 Flyingis 阅读(1699) | 评论 (0)编辑 收藏

GIS空间分析

    作者:Flyingis

    空间分析是为了解决地理空间问题而进行的数据分析与数据挖掘,是从GIS目标之间的空间关系中获取派生的信息和新的知识,是从一个或多个空间数据图层中获取信息的过程。空间分析通过地理计算和空间表达挖掘潜在的空间信息,其本质包括探测空间数据中的模式;研究数据间的关系并建立空间数据模型;使得空间数据更为直观表达出其潜在含义;改进地理空间事件的预测和控制能力。

    空间分析主要通过空间数据和空间模型的联合分析来挖掘空间目标的潜在信息,而这些空间目标的基本信息,无非是其空间位置、分布、形态、距离、方位、拓扑关系等,其中距离、方位、拓扑关系组成了空间目标的空间关系,它是地理实体之间的空间特性,可以作为数据组织、查询、分析和推理的基础。通过将地理空间目标划分为点、线、面不同的类型,可以获得这些不同类型目标的形态结构。将空间目标的空间数据和属性数据结合起来,可以进行许多特定任务的空间计算与分析。

    现在不少空间分析方法已经在GIS软件中实现,ArcGIS ToolsBox中就集成了大量的空间分析工具,例如空间信息分类、叠加、网络分析、领域分析、地统计分析等等,另外,还有一系列适应地理空间数据的高性能计算模型和方法,例如人工神经网络、模拟退火算法、遗传算法等等。但总的来说,目前在GIS软件中实现的专业空间分析模块还比较少,由于空间分析理论自身的不完善,也使得还没有比较全面、权威的软件包集成于GIS软件中。目前GIS软件与空间分析软件相结合的方式有两种,一种是高度耦合,一种是松散耦合。

    高度耦合结构即把空间分析模块嵌入到GIS软件包中,供用户直接从图形界面中选择各种功能,GIS中相关的数据直接可以参与到空间分析计算中,这种方式方便了用户,但代价是开发费用较高,实现周期长。目前也只有少数的大型GIS公司才会深入的涉足到高耦合结构GIS软件的设计与开发中,例如美国ESRI公司。

    松耦合结构则是在相对独立的GIS软件和空间分析软件之间使用一个数据交换接口,GIS软件中的数据通过接口为空间分析软件提供基本的分析数据源,经空间分析软件计算出的结果通过接口以图形的方式显示在GIS软件中,实现这种架构方式相对容易,费用也相对较低,一般可以使用开源的GIS软件即可实现这种结构。

    在GIS中开发有效的空间分析工具相对难度较大,《地理空间数据分析与GIS》中将GIS环境下空间分析方法分为六种:

1.  确定性空间分析
2.  探索性空间数据分析
3.  时空数据分析
4.  专业模型集成分析
5.  智能化空间分析
6.  可视化空间分析

posted @ 2006-04-07 16:13 Flyingis 阅读(5191) | 评论 (4)编辑 收藏

地理空间数据挖掘

    作者:Flyingis

    数据挖掘是一个由数据库、人工智能、数理统计和可视化等多学科与技术交叉、渗透、融合形成的交叉学科。地理空间数据挖掘(Geospatial Data Mining)是数据挖掘的一个研究分支,即从地理空间数据库中挖掘时空系统中潜在的、有价值的信息、规律和知识的过程,包括空间模式与特征、空间与非空间数据之间的概要关系等。数据挖掘可以用来模拟事物的一种变化方式,通过一些先验的知识或样本来判断事物未来的发展状况或某种状态。地理空间数据挖掘则可以作为一种可用的科学方法来解决一些地学相关的问题,对地学状况的变化作出分析和预测,这些分析很多都是基于对空间分析的基础上的,因此地理空间数据挖掘的根本是事物的空间特性,例如方位、距离、拓扑关系等等。

    数据挖掘需要通过访问正确、完整和集成的数据库才能进行深层次的分析,挖掘出有用的信息,而这些正确的、完整的数据信息则是由数据立方体所提供的,其联机分析功能OLAP为数据挖掘提供了一个良好的操作平台。

    地理空间数据挖掘典型方法主要有以下几种:
1.  地理空间统计方法
    地理空间统计是指分析地理空间数据的统计方法,主要是利用了空间中邻近的要素通常比相距较远的要素具有较高的相似性这一原理。该模型可以分为三类:地统计、格网空间模型和空间点分步形态。
2.  地理空间聚类方法
    地理空间数据聚类是按照某种距离度量准则,在大型、多维数据集中标识出聚类或稠密分布的区域,从而发现数据集的整体空间分步模式。该方法主要分为四类:分割法、层次法、基于密度的方法及基于网格的方法。
3.  地理空间关联分析
    地理空间关联分析利用空间关联规则提取算法发现空间数据库中空间目标间的关联程度,从而进行空间数据关联分析的知识发现研究,其核心内容是挖掘空间关联规则。
4.  地理空间分类与预测分析
    地理空间分类与预测是根据已知的分类模型把数据库中的数据映射到给定类别中,进行数据趋势预测分析的方法。人工神经网络可以作为该方法的典型技术应用于实际研究中。
5.  异常值分析
    顾名思义,异常值分析即将数据库中与通常的行为或数据模型不一致的数据提取出来的分析方法。通过这种方法可以提取出数据库中的异常信息或噪声数据,有时也会导致隐藏的重要数据丢失。异常值分析方法主要有三种:基于统计的异常值分析、基于距离的异常值探测、基于偏差的异常值探测。

    使用地理空间数据挖掘方法进行数据分析、信息提取时,Mathlab是一个非常好的辅助工具,很多函数库和可视化界面可以方便的使用,也可以很好的判断算法是否达到了应用要求,同时还可以作为其他语言实现数据挖掘方法的一种对比参考。

参考资料:
GIS空间分析原理与方法

posted @ 2006-04-05 19:58 Flyingis 阅读(2018) | 评论 (2)编辑 收藏

地理空间数据处理与模型

作者: Flyingis

Michael F G 说过:“地理信息系统真正的功能在于它利用空间分析技术对空间数据的分析”,而不仅仅是停留在数据库型的 GIS 层面上,需要将关注点从数据库创建和系统开发建设,逐步转移到关注空间分析和空间建模,挖掘对科学决策具有指导意义的信息,解决复杂多变的地学应用问题,例如空间分析、预测预报、决策支持等。

地理空间数据处理与建模的重要技术方法一般涉及到数量地理学、 GIS 、地理计算、数据挖掘等知识领域。地理空间数据分析是地理学和地理信息科学的重要研究内容,它通过研究地理空间数据及其相应分析理论、方法和技术,探索、证明地理要素之间的关系,揭示地理特征和过程的内在规律和机理,实现对地理空间信息的认知、解释、预测、调控。

1.  数量地理学

数量化方法在感知、认识和解释现实世界的各种自然、人文、社会现象过程的相互关系中起着定性方法不能替代的作用。不论是学术研究中,还是实际决策中,不论是理工科学中,还是人文管理中,数量化的方法总是更让人觉得合理可信,通过表格化、图形化的形式表达出来,作为结论论断的有力支持,通常也可以说是定量化的分析方法。数量地理学是地理学领域中最先采用数学原理方法来探讨地理数据分析处理与建模的学科,主要涉及的分析模拟方法是地理系统分析、随机数学方法和地理系统数学模拟。

2.  地理信息系统

地理信息是一门学科,是描述、存储、分析和输出空间信息的理论和方法的一门新兴的交叉学科;另一方面,地理信息系统是一个技术系统,是以地理空间数据库为基础,采用地理模型分析方法,适时提供多种空间和动态的地理信息,为地理研究和地理决策服务的计算机技术系统 ( 经典定义 ) 。一般,我们利用 GIS 来反应客观显示世界抽象化的数字模型,对地理空间数据进行管理、显示与制图,最重要的是,可以用来对数据进行模拟分析,实现可视化和对现实世界的虚拟,提供决策的依据或直接进行决策分析。

3.  地理计算

地理计算本质上可认为是对地理学时间与空间问题所进行的基于计算机的定量化分析,它是一系列的程序或算法的应用过程和结果,不同的算法例如神经网络、模糊逻辑、遗传算法等产生的结果也会不同,一般可以通过和以往成果的对比,来论证自己算法更为优秀更为符合实际,或根本就是一个失败的计算过程。

其中涉及到的理论知识主要有 GIS 建库,人工智能技术和智能计算技术 ( 人工神经网络模型、模糊逻辑模型、遗传算法模型、元胞自动机模型、分形理论等等 ) ,高性能计算服务系统。通过这些知识体系建立一种动态模型,来反应地理空间的动态特性,强调作为地理空间基本部分的动态组成。

 

参考文献:

地理信息系统——原理、方法和应用

GIS 空间分析原理与方法

posted @ 2006-04-03 15:53 Flyingis 阅读(1844) | 评论 (2)编辑 收藏

[Java Puzzlers]表达式随想

    作者:Flyingis

    前段时间到书店抱了几本书回来,虽说网上有很多电子版的资料,但有时候觉得一些比较经典、自己比较喜欢的书籍还是有必要捧在手上细读的,《Java Puzzlers》就是其中之一,没事的时候就喜欢拿出来翻翻,怕自己像看新闻报纸一样看过就淡忘了,还是略作笔记让自己多份思考。

    软件开发人员无论最初是从哪种语言开始学习的,首先都要掌握该语言的编程基础,例如语句、表达式、变量、数据类型、运算符、字符串等等,这些基础性的知识简单,但细节却比较繁琐,不同的编译器也会有不同的编译规则。以前寝室有同学考过的全国计算机等级考试二级C语言的试题中,语言的础规则是出题者最热衷的题形之一,曾经也觉得出题者无聊,只重理论不看实际,毕竟一些表达方法和书写格式可以通过规范来约束简化,但是作为一名程序员,一个专业的开发人员,应该了解自己所使用语言的基础规则,有时候一些程序的BUG就是存在于这些不起眼,或是自己认为应该没有问题的地方。

    Java语言的表达式和C/C++比较相近,但也存在一些差异,这些差异不仅仅是那些看得见的差异,还有隐性的,例如相同的表达式,编译的规则不同。因此,我们需要理解Java表达式的一些基础性知识,加深认识。

1.  要精确表达一个浮点型变量,应该使用BigDecimal对象来构造这个实例,使用float或double在一般情况下只是提供了在一定精度范围下的一种近似,不能产生精确的结果。常用的数据库中都有与BigDecimal相对应的数据类型,有的更为详细。
2.  对于 long value = 30 * 300 * 3000 * 3000; 来说,long类型可以完整保存右边表达式计算的结果,但是右边表达式的计算是按照int类型进行的,只有当右边表达式计算完成后才会转换为long类型,在计算过程中,右边表达式的值就已经超出int范围,因此会出现计算溢出。
3.  通常我们使用最多的是十进制计算,和十进制不同的是,当十六进制或八进制常量的最高位被置位时,该常量是负值。
4.  注意数据类型之间的相互转换(特别是char类型和其他类型间的转换),以及三目运算符的第二和第三操作数类型不一致的情况处理。
5.  在C/C++中,操作符的操作数是从右向左计算,Java中相反。
6.  复合赋值操作和简单赋值操作在一般情况下是相同的,例如 x *= y 和 x = x * y ,但是当x和y类型不同时情况有所变化,例如当x为short类型,y为double类型时,x *= y的结果虽然和想象的有些出入,至少可以编译通过,但后者赋值却是非法的。

    大家可以继续补充……

posted @ 2006-03-30 23:47 Flyingis 阅读(1107) | 评论 (1)编辑 收藏

MVC的一幅简单素描

 作者:Flyingis

 

素描工具: Struts + Hibernate 3

素描对象:一个足够简单的基于 MVC Web 应用

目的:使用 Struts 分离业务逻辑与表现,使用 Hibernate 分离数据操作与业务逻辑,整理一种基本的 MVC 开发思路。

 

1. 素描框架
 

    该素描主要体现在系统层次的功能划分,系统结构的组织与设计上,素描足够简单,数据库中只涉及一张表:

    学生信息(学生编号、姓名、性别、年龄、专业信息)--Student( id, name, gender, age, specialty_id )

  • 系统设计

    公共类的设计与实现

    各模块的详细设计,主要描述一个基本的 CRUD 操作,以及对象数据传递

  • 系统的部署、测试与发布

2. 公共类设计
 

    基本的 CRUD 操作封装在基本的帮助类 HibernateHelper 中,实现 Object load(Class theClass, java.io.Serializable id) Query createQuery(String queryString) void setQueryParameter(Query query, String name, Object val) List list(Query query) void save(Object o) void update(Object o) void delete(Object o) void saveOrUpdate(Object o) 等这些基本方法。
 

    常量单独封装在 Constants 类中。

 

3. 各种对象设计

  • ActionForm:StudentForm-- 用于视图层与控制层之间传递数据。
  • 接口 StudentIf-- 实现了学生数据对象 Bean 所需要的所有接口方法。
  • 学生数据对象 StudentData-- 实现了记录学生对象数据的功能,并可以用作数据交互的传输对象,它实现了接口 Serializable StudentIf
  • 学生实体 Bean StudentBean-- 实现了学生实体的所有属性,它实现了接口 Serializable StudentIf

4. 对象管理实现类
 

    业务逻辑处理为项目的核心,直接关系到项目是否符合用户需求。因此,我们可以单独设计一个对象管理实现类 ManagerFacade,定义处理业务对象的CRUD操作,以增加学生信息为例public StudentIf addStudent(StudentIf student)。学生数据对象StudentDataAction中通过StudentForm接收到表现层传入的数据,然后作为ManagerFacade对象的addStudent方法的参数传入方法内,在方法体内声明学生实体StudentBean的一个对象,将学生数据对象即传入参数中的属性值赋给实体对象,然后调用公共类HibernateHelper的save方法完成数据库操作。其他基本操作与此类似,这样设计似乎对象较多,但各层之间分工明确,有利于降藕。

    另外,在数据传递过程中,还会涉及到数据类型的转换,可以专门设计帮助类来完成。

 

5. 页面 UI 设计
 

    除了设计美观的页面外,最重要的是页面结构要符合项目需要,并提供一定的使用体验,有时候简单实用就是最好。如果可以对用户浏览器统一规范要求,或是基本不会屏蔽 Javascript ,数据格式的控制可以放在客户端用 Javascript 实现。

 

6. 系统的部署、测试与发布。

posted @ 2006-03-27 17:50 Flyingis 阅读(2610) | 评论 (6)编辑 收藏

Web应用系统设计原则

    作者: Flyingis

    和C/S结构相比,B/S结构受限于网络带宽不利于进行大数据量的统计分析,网络传输存在潜在的安全问题,还有用户界面不及C/S结构友好等等,但随着网络带宽和网络应用的发展,加上AJAX技术的流行,使得现在越来越多的MIS系统或基于MIS系统的专业化应用系统都开始倾向于采用B/S结构进行设计,充分利用B/S结构的优点。但是,要充分发挥Web应用的内在潜力,挖掘应用深度和扩大适应能力,需要采用先进的应用架构和以实用为根本准则,使得系统既能满足业务需求,又能适应将来发展需要。因此,在开发Web应用系统时需要尽量遵循Web应用系统设计原则。

    实用性原则:这是所有应用软件最基本的原则,直接衡量系统的成败,每一个提交到用户手中的系统都应该是实用的,能解决用户的实际问题,否则该设计就是垃圾。

    适应性和可扩展性原则:系统需要具备一定的适应能力,特别是Web应用要能适应于多种运行环境,来应对未来变化的环境和需求。可扩展性主要体现在系统易于扩展,例如可以采用分布式设计、系统结构模块化设计,系统架构可以根据网络环境和用户的访问量而适时调整,从某种程度上说,这也是系统的适应性。

    可靠性原则:系统应该是可靠的,在出现异常的时候应该有人性化的异常信息方便用户理解原因,或采取适当的应对方案,在设计业务量比较大的时候可采用先进的嵌入式技术来保证业务的流畅运行。

    可维护性和可管理性原则:Web系统应该有一个完善的管理机制,而可维护性和可管理性是重要的两个指标。

    安全性原则:现在的计算机病毒几乎都来自于网络,Web应用应尽量采用五层安全体系,即网络层安全、系统安全、用户安全、用户程序的安全和数据安全。系统必须具备高可靠性,对使用信息进行严格的权限管理,技术上,应采用严格的安全与保密措施,保证系统的可靠性、保密性和数据一致性等。

    总体规划、分层实施原则:在开始设计之前应该对Web系统进行总体设计,然后在总体设计指导下分步开发。基于J2EE技术的应用系统是一个融合了多元信息的集成系统,现在一般都采用分层开发:表现层、控制层、业务逻辑层、模型层、数据访问层等,在适应系统需求的准则下,设计低耦合的分层结构,利于团队成员的分工协作,提高开发效率,降低项目风险,实现各个模块的功能设计,完成整个系统的开发。

posted @ 2006-03-25 15:28 Flyingis 阅读(5657) | 评论 (1)编辑 收藏

重温Struts--ActionForm

作者:Flyingis

ActionForm Struts设计中比较有争议的一个概念,在某些情况下也许不会使用到ActionForm,具体可以参照《Struts Action的多种角色一文。尽管如此,ActionForm在许多应用的开发中都实现了重要的功能,它是Struts框架提供的DTO,用于在视图层和控制层之间传递HTML表单数据,控制层可以从ActionForm Bean中读取用户输入的表单数据,也可以把来自模型层的数据存放到ActionForm Bean中,返回给视图,即使用它的主要目的是字段采集、类型转换器、以及传输对象等。对于ActionForm BeanMVC中所处层次结构的理解,可以参考《剖析MVC中的各种Object

ActionForm 的基本功能

1. 字段采集

Web应用程序开发过程中,数据的采集是最基本的一个环节,而html定义的数据输入控件和http定义的数据传输协议非常简单,因此在Struts中设计了ActionForm来弥补这种不足。Strutshttp参数处理的方法是将输入参数传递到JavaBean属性来进行处理,当ActionForm的属性与某个请求参数匹配,框架自动以参数的值设置属性。

2. 数据校验器

Html 没有在数据提交之前对数据进行校验的能力,使用javascript可以做到这些,优点在于可以减轻服务器负担,但javascript经常会被浏览器禁止,因此,在StrutsActionForm实现了部分数据校验的功能,当输入数据不符合要求时,页面将被返回到数据数据页面,要求用户重新输入。一般情况下,ActionForm属性定义为String类型,以便对各种输入进行捕获。另外,还可以用ActionFormAction对输入数据进行双重校验,ActionForm校验数据类型是否正确,Action校验该数据是否满足业务层的其他要求。

3. 类型转换

HTML 表单中的数据类型一般是Stringboolean类型,通过在ActionForm Bean中实现Helper方法,可以实现属性类型的转换。

4. 传输对象

ActionForm 可以作为其他Bean的数据载体,它装载的数据通常对应着持久层中的不止一个实体。

posted @ 2006-03-18 22:40 Flyingis 阅读(827) | 评论 (0)编辑 收藏

剖析MVC中的各种Object

    作者: Flyingis

    在Web应用和J2EE框架中经常可以碰到各种Object相关的名词,在网上搜索了一下,讨论各种Object术语的帖子一大筐,大的讨论整个框架,小的描述各个层次之间的细微差别,甚至有钻牛角尖之嫌。 BlogJava 上也有讨论VO和PO的贴子,例如 非飞 《各层共享使用PO的代价》 等。其实无论怎么讨论,这些术语、分层结构、应用框架无非都是为我们的应用而服务的,因此,我们需要的是理解这些术语提出的意义,是理解我们的项目需求,是理解我们采用的框架结构能否最大限度的满足项目的需要。

    在刚刚学习MVC/Model2之前,我是不了解VO/TO/PO/DTO/BO等等这些术语的含义的,至少理解上只是停留在浅层面,现在多看了一些,做了一点项目,多了些想法,但肯定还是存在理解上的偏差或误解,欢迎大家讨论指出!

    VO: 通常指ValueObject或ViewObject。ViewObject指的是UI需要的对象,Struts的FormBean就是其中的一种,它是Value Object和Transfer Object的总称。

    TO: Transfer Object,它和Value Object的区别可以参考Patterns of Enterprise Application Architecture。

    PO: Persistent Object,即可以被持久化的实体对象。

   
POJO : Plain Ordinary Java Object。

    DTO: Data Transfer Object,J2EE 中常用的一种设计模式,现在一般可以将使用Value Object的模式称为DTO模式,在
Jdon 上一篇《ValueObject和DTO模式的一些疑问》 阐述了两者的关系。

    BO: Business Object,可以分为三种情况,只包含业务对象的属性,或只包含业务方法,或两者都包含。对于BO的详细讨论,可以
参见这里

    这些概念经常交错在一起提出,给初学者造成了一些理解上的困难,其实只需要理顺下面几点,基本上就能弄清楚层次之前的前后关系和如何合理使用这些对象。

    1. VO能否和PO相同。首先回答是肯定的,VO是概念模型的一种抽象反映,当一个业务实体可以用一个物理实体表示的时候,VO和PO属性相同,那么它们是相等的。例如学生成绩管理系统中,成绩表单业务实体中包含学生信息、课程信息、成绩等,此时它已经不能用一个物理实体所能描述,而其中的学生信息,其VO和PO在属性上是一样的,此时的VO和PO相同。

    2. PO能否代替VO。仅仅从功能实现上来说,当VO和PO相同的时候,PO可以代替VO,这样可以减少一些代码量,但需要注意的是,这样会带来一些问题:当一个业务实体需要多个物理实体来表达的时候,在客户端显示一个业务实体就会多次访问数据库,即进行多次单表访问,非视图;当一个业务实体属性远少于一个物理实体的时候,可能会因装载过多不必要的数据而影响网络传输;对物理实体进行改动的时候会直接影响到表现层。简单的说,这样做增加了代码的耦合性,也增加了代码维护的难度,项目的可扩展性也大大降低,如果仅仅是为了减少代码量而付出这些代将显然是不值的,当然极为简单的应用可以考虑,一切从项目实际出发。

    3. VO包含的属性可以多于PO、少于PO、或等于PO中的属性。

    4. 一个基于Struts应用的简单数据提交流程(VO和PO单独存在):HTML 页面中包含了基本的信息,例如文本框、下拉框、单选等,构建一个ActionForm Bean与之一一对应,它是Web层数据的表示,当Web页面的操作流程发生改变的时候,需要对它进行修改,但不能将修改传递到业务层和持久层。然后Action读取ActionForm Bean的属性,构造PO对象,调用BO ,当BO收到这个PO之后,调用DAO接口方法,对PO进行持久化操作,完成数据的提交。这里,PO在业务层和持久层之间,没有被传递到Web层的View中去。

    5. 一个基于Struts应用的简单数据查询流程(VO和PO单独存在):Action读取ActionForm Bean中的查询属性信息,然后调用BO,BO获取ActionForm Bean之后调用DAO接口进行查询,返回所要查询的PO对象,交给Action,Action通过该PO构建 ActionForm Bean,通过request.setAttribute()或session.setAttribute(),重定向到查询结果页面输出需要的信息。

    6. 表现层中的字段一般定义为String或boolean类型,因此VO中的属性在传到Action并构建PO对象时需要进行数据类型的转换,或由ActionForm的helper方法来进行转换。

    参考文章和贴子:
   
http://www.jdon.com/jive/article.jsp?forum=91&thread=23672
    http://www.jdon.com/jive/article.jsp?forum=91&thread=21571
    http://www.hibernate.org.cn/viewtopic.php?t=627&postdays=0&postorder=asc&start=0
   
http://bbs.hidotnet.com/704/ShowPost.aspx
    http://lifework.cnblogs.com/archive/2005/09/03/229596.html
    http://www.microsoft.com/china/MSDN/library/architecture/patterns/esp/DesDTO.mspx  

posted @ 2006-03-17 00:28 Flyingis 阅读(2595) | 评论 (0)编辑 收藏

重温Struts--标签

作者:Flyingis

Struts标签提供了大部分应用来满足创建MVC架构表现页面的所有功能。在一个MVC应用中,请求并不是直接到达表现页面,而是首先经过控制器,仅当业务数据被获取,并且业务规则被应用后,控制器才处理表现页面。页面的职责就是输出结果和捕获用户输入,Struts标签的功能目的就在于此。

虽说Struts标签库能满足我们大多数情况下的需要,但不是唯一可用的标签,例如JSTL标签、DisplayTag等等。Struts标签和其他各种标签的基本使用方法在各种书本上都有介绍,这里总结一下标签使用中的个人体会,并不断更新。

1.        Struts中包含三个标签库,BeanHTMLLogic,其中HTML标签库依赖于框架,其他大部分标签不依赖于框架,可以在其他应用中使用。

2.        Struts HTML标签和一般HTML标签具有一定的对应关系,但也存在一点不同。使用ScriptletHTML标签需要在使用前在页面中将Form Bean声明为一个脚本变量,Struts标签则不需要声明就能找到该Bean。在默认情况下,Struts标签将对剩下的表单使用同一个Bean,所以不需要对每一个控件都进行指定。例如:
<input type=“text” name=“username” value=“<%=user.getUsername()%>”/>
使用Struts HTML标签
<html:text property=“username”>

3.        Struts HTML标签和一般HTML标签具有一定的对应关系,但存在几个特例,在Struts HTML标签中,Messages / errors / rewrite分别用来表示显示一组消息、显示一组错误消息、输出一个编码的URL路径,而这些在一般HTML标签中就不存在。

4.        HTML有时需要处理特殊的字符,包括标签的括号、&符号以及其他的内容,如果这些字符作为文本字段的一部分,可能会出现错误并造成HTML崩溃。如果确实需要在数据中存储这些字符,可以在网页中进行设置,使得这些字符不被页面过滤成为特殊字符,例如:
<bean:write name=“UserForm” property=“username” filter=“false”/>

5.        使用<html:password>时,如果页面校验错误,password属性将从Form Bean中读回,并放置在password标签中。虽然密码会被浏览器用符号隐藏,但在HTML源代码中仍然可以看到,存在安全上的隐患,因此可以在标签中加入redisplay=false来保证password总是以空白状态显示给用户。

6.        提供一个Javascript的返回按钮,可以定义一个没有属性的简单表单,Struts配置文件:
<action path=“/adduser”
      type=“org.apache.struts.ForwardAction”
      name=“BlankForm”
      scope=“request”
      validate=“false”
      parameter=“/user.do”>
JSP
页面:
<html:form action=“/adduser”>
<html:button property=“page” onClick=“history.go(-1)”>here</html:button>
</html:form>

posted @ 2006-03-12 09:23 Flyingis 阅读(2636) | 评论 (0)编辑 收藏

重温Struts--Validator和Tiles

作者:Flyingis

今天要回顾的是ValidatorTiles以及简单的Plugin实现,刚刚登录blogjava就发现Mustang已经发了两篇好文《在Struts中使用Validator实现可配置的信息校验() ()》,本文则从实现流程来总结Validator的使用方法,并针对ValidatorTilesStruts PlugIn插件略谈一些个人心得。

Validator

在使用ActionForm时,将数据的验证工作放在validator()方法中虽说是一个可行的方法,但在ActionForm中编写特定的验证逻辑会降低ActionForm的重用性,并给系统的维护带来麻烦。Validator框架可以将验证逻辑移至ActionForm之外,实现Javascript客户端验证或服务器段验证。具体实现Validator验证步骤如下:

1.        Validator是以plugin的方式来扩充ActionServlet功能的,需要在Struts-config.xml中声明这个plugin

2.        导入Validator中的资源信息,用来向用户提示验证中出现的异常消息。Validator可以支持国际化信息,为每一个国际化信息提供对应的资源信息。

3.        利用validaton.xml文件来定义用户需要验证的每一个JSP表单中的每一个字段的验证规则,其中可以利用validator-rules.xml中已经设计好了的验证器,也可以自定义验证方式。

4.        客户端验证需要validator-rules.xml中已提供的验证规则,或是自定义规则,然后在jsp页面中声明<html:form action=“/action.do” onsubmit=“return validateActionForm(this);”>,加上可以生成实现验证的Javascript代码<html:javascript formName=“ActionForm” staticJavascript=“true”/>。服务器端验证同样需要validator-rules.xml中已提供的验证规则,或是自定义规则,另外,实现验证的ActionForm需要是DynaActionForm的子类,和客户端验证不同的是,在捕获服务器端错误消息时,jsp页面中需要嵌入代码

<html:messages id=“error”>

  <bean:write name=“error”/>

</html:messages>

在配置和设计Web系统验证功能的时候,需要注意的是要理解在validaton.xml中定义验证规则的时候每个参数的具体功能,我最初使用Validator的时候就因为参数混淆而验证失败,费了一点时间。还有就是自定义验证规则时,需要注意每个参数的具体含义,例如在某种情况下,validaton.xml<var-name>myproperty</var-name>中自定义的属性myproperty需要和自己编写的验证器类中的代码一致等等。

Tiles

Tiles是一个模板机制,它可以让网页的配置框架和内容分离,提供一个版面管理机制。通常有两种方式管理Tiles配置资源,一种使用XML,另一种使用JSP页面直接管理。

使用XML配置的Tiles可以支持国际化,例如可以另存为tiles-defs.xml并命名为tiles-defs_zh.xml,将encoding改为GB2312,这样可以在配置中使用中文。使用XML配置文件可以方便的实现版面配置和内容的分离,并且能扩充某个定义,达到重新定义其中所管理页面资源的目的。使用JSP页面直接定义管理版面的配置资源更为简单和灵活,同样可以和xml一样重新定义网页的地址。不使用JSP框架页面而是直接在JSP页面中使用配置页面,可以不用额外去定义管理文件,但缺点是无法重用这个页面定义的内容。

TilesCSS结合起来,基本上能满足一般页面控制的需要。

PlugIn插件

通过继承ActionSerlvet,重写它的init()方法,修改或增减它的初始化资源来达到改变ActionServlet功能的方法,这从软件架构角度上来讲并不是一个好方法。Struts1.1之后,可以通过PlugIn接口来实现动态增减ActionServlet功能的目的。ActionServlet加载后,会执行实现PlugIn接口的类的init()方法,在ActionServlet终止前,执行实现PlugIn接口的类的destroy()方法。ValidatorTiles就是利用这种方式来扩充Struts功能的。

写到这里,感觉使用好ValidatorTilesPlugIn插件最重要的就是对配置元素的理解,和程序调用流程的掌握,了解到Struts的插件机制是如何运转的,以此来扩充Web应用程序的功能,提供更好的用户体验。

posted @ 2006-03-08 14:52 Flyingis 阅读(1970) | 评论 (2)编辑 收藏

重温Struts--Action

作者:Flyingis

Struts中,ActionServlet担任分配工作的控制器角色,实际的工作是交给Action对象来进行的。ActionStruts框架的核心类之一,它主要用来访问业务层、为表现层准备数据对象和处理错误异常。

ActionStruts框架中基本上属于控制器的角色,通常不建议在Action中加入过多的业务逻辑,将业务逻辑封装在其他的类中,然后在Action中建立这些类的对象,调用对象的方法来实现业务功能。比较遗憾的是,当业务逻辑中出现异常的时候没有办法将异常说明在页面中直接反应出来,展现给用户,在Action中控制这些异常可以做到这点。

要更详细的了解Action的工作机理,就要剖析ActionServlet控制器的工作流程及其核心方法。在Struts中,担任控制器角色的核心是ActionServlet,所有的请求都必须先通过它,而对所有请求的处理是交付给RequestProcessor来完成的,既然处理请求的任务是交给RequestProcessor来完成,那么可以直接查看org.apche.struts.action.RequestProcessor类,看其process()方法实现了哪些功能,从源代码中的英文注释我们可以更深入了解到整个处理过程,很多书籍和网上不少文章都描述了这个过程,还有典型的处理过程图示,这里就不再详述。只是从这个过程可以看出,通过继承ActionServlet来定义自己的控制器请求意义不大,重写init()方法倒是可以修改初始化工作,如果需要定义自己的控制器,可以继承RequestProcessor并修改其中的process()方法来实现。

Struts应用中,除了直接继承org.apache.struts.action.Action类实现Action功能外,Struts还提供了其他几种Action类来满足某种特定需要,这些书本上已经写了很多,这里只是照葫芦画瓢略作总结:

ForwardAction—当需要从一个页面转到另一个页面或资源时,不提倡直接使用页面或资源路径调用,除了与MVC/Model2架构向背之外,有时还会带来其他的问题,前几天在网上看到一个帖子就是因为直接调用资源出现了异常,具体出自于哪里没有记住。这里,应该通过控制器使用ForwardAction来完成链接的跳转,使用属性parameter设定forward的链接地址。

IncludeAction—ForwardAction类似,当需要引入一个资源时,可以使用IncludeAction来实现,属性parameter设定include的链接地址。

SwitchAction—用于从一个模块转换至另一个模块,一种方法是使用相对于Context的路径来进行forward查找,另外一种就是使用SwithAction,它需要在请求中带两个参数,一个是prefix用来指定模块前缀名称,一个是page用来指定相对于模块的资源路径。

DispatchAction—随着Struts Web应用规模扩大,维护Action复杂度提高,可以使用模块化来管理Action。另一方面,当一个页面需要多个Action时,我们就可以使用DispatchAction来将一个页面中所有相关的动作放在一个action类中实现,此时不需要重定义execute()方法,它已经在DispatchAction抽象类中定义,我们需要编写自己的方法来响应一个页面上不同的动作。它的关键属性是parameter

LookupDispatchAction—它是DispatchAction的子类,不同的是,当页面按钮的property属性相同的时候,它可以通过查询资源文件来确定相应的动作,这个功能主要是通过重写getKeyMethodMap()方法实现的。

posted @ 2006-03-06 00:07 Flyingis 阅读(1178) | 评论 (0)编辑 收藏

重温Struts--ActionMapping和ActionForward

作者:Flyingis

前段时间用Struts完成一个小项目,当时还没有来到blogjava,很多东西也没有记录。现在花一点时间,将整个Struts应用重新温习一遍,重新挖掘项目开发过程中没有注意到的知识点,并写下自己的一些心得与体会。

ActionMapping

ActionMapping将对Struts应用中有效的业务逻辑进行分类,当一个请求到达时,ActionSevletActionMapping目录中查找对应的信息。ActionMappingStruts应用的一个核心设计,当需要了解一个Struts应用,或编写一个新的Struts应用的时候,都应该从ActionMapping入手。ActionMapping有较多的属性信息,具体参考相关文档。

ActionForward

ActionForwardStruts的核心类之一,其基类仅有4个属性:name / path / redirect / classname。在基于StrutsWeb应用程序开发过程中,Action操作完毕后程序会通过Struts的配置文件struts-config.xml链接到指定的ActionForward,传到Struts的核心类ActionServletActionServlet使用ActionForward提供的路径,将控制传递给下一个步骤。ActionForward控制接下来程序的走向。ActionForward代表一个应用的URI,它包括路径和参数,例如:

path=“/modify.do?method=edit&id=10”

ActionForward的参数除了在struts-config.xml和页面中设置外,还可以通过在Action类中添加参数,或重新在Action中创建一个ActionForward

ActionForward中有一个重要的属性redirect,当redirect=false时,将保存存储在http请求和请求上下文中的所有内容,仅在同一个应用中可用。当redirect=true时,Web客户端进行一次新的http请求,请求的资源可以在同一个应用中,也可以不在,原来的请求参数不再保存,原来的请求上下文也被清除,新的http请求仅包含ActionForwardpath属性里所包含的参数。如果在同一个应用中,用户会话的上下文会被维护。

ActionForward分为全局转发和局部转发,ActionMapping对象的findForward方法首先会检查局部转发列表,查找失败就会到全局转发列表中查找。书写格式中,我们一般将全局变量定义为String常数,避免误解,使得转发列表结构清晰易读。

在项目开发过程中经常碰到一种情况,当页面已经改变了,浏览器中的地址如/modify.do/modify.jsp却没有变化,当时没有考虑这么细,虽然存在疑问,但没有影响到程序功能的实现,因此忽略过去了,今天查找了一些资料才弄清楚。客户端浏览器显示的是浏览器最后被给定的URL,当URL被提交后,在某个组件返回一个响应给浏览器之前,Web应用可能已经转发请求多次,而这些过程都发生在服务器端,客户端浏览器并不知道有什么变化。当一个http响应被返回时,它并没有包含地址栏的值,所以浏览器仅仅显示其用来作为初始请求的地址。通过使用redirect可以改变浏览器地址的显示,因为这样可以向浏览器提交一个新的请求,但付出的代价是数据不能通过请求上下文传递到页面,这也是使用forwardredirect的差异之一。

posted @ 2006-03-05 10:40 Flyingis 阅读(1424) | 评论 (0)编辑 收藏

IntelliJ IDEA 5.1 初步感受 + crack

作者:Flyingis

最初开始接触Java的时候总喜欢跟潮流,当经历JDK+UltraEdit的洗礼之后,便开始使用JBuilder7/8/9,然后是Eclipse3.0.1加上各种插件,用于Web系统开发,使用感觉还不错,加上Eclipse有众多优秀插件的支持,因此就没有再去琢磨其他的IDE环境。

前两年就听说过IntelliJ IDEA,当时是在《CSDN开发高手》杂志上看到一篇介绍它的文章,还记得上面说IntelliJ IDEA显著特征之一,就是方便的即时分析和重构功能,当时它的版本还是3.0.5,转眼之间现在IntelliJ IDEA 5.1都已经发布了,基本功能和易用性都得到了很大程度的改观和加强。在安装好软件以后,单是看开发环境中Refactor下的菜单项就知道它Refactoring的功底了。现在IntelliJ IDEA 5.1也开始支持插件,第一次进入开发界面整个右边栏目全部显示的是个人的插件和IDE已经集成的插件,虽然IntelliJ IDEA的开源插件还远不如Eclipse,但是这些才刚刚开始,IntelliJ IDEA 5.1Hibernate插件Hibero1.2已经发布,相信在这方面IntelliJ IDEA会越做越好。除此之外,IntelliJ IDEA似乎并不必Eclipse弱,甚至很多方面都比Eclipse强,例如全面支持Web开发、优秀的重构、众多实用插件的集成、方便的环境设置等等,在网上有很多这方面的文章。另外,过去曾经听说IntelliJ IDEA对资源占用量比较大,其实只要是Java IDE,就没有一盏省油的灯,刚才简单比较了一下,打开IntelliJ IDEA 5.1内存占用量是74M多,打开Eclipse 3.1内存占用大于88M,在机器配置越来越高,内存价格越来越便宜的今天,这种问题也不用过多考虑了,Visual Studio 2005的消耗量更大。

总之,个人感觉IntelliJ IDEA完全可以和EclipseJBuilder等开发环境相媲美,甚至更优秀,收费可能是它进一步扩大用户群的阻碍之一,不管怎么样,它给Java开发人员提供了另外的一种选择。

官方资源:

http://www.intellij.com

http://www.jetbrains.com

下载:

http://www.jetbrains.com/idea/download/

download crack

相关文章:

SUN发布开源Netbeans 5.0

Netbeans拉近和Eclipse差距

 

posted @ 2006-02-26 21:48 Flyingis 阅读(5096) | 评论 (16)编辑 收藏

Google启动个人网站服务

    Google为每个Gmail用户准备了100MB免费个人网站空间,并且没有任何广告,这和微软的MSN形成了一种对比。现在感觉不论什么事情,Google总能把微软先甩在后面,然后让微软去追赶,这得益于Google的经营模式,得益于Google的简约与实用,也得益于Google较好的把握住了用户潜在的需求。
   
   
点击这里来创建自己的空间

    近段时间其他Google相关热点文章参考以下链接:

   
Google的Offer
    Google新服务--出行路线规划服务
     wallop和orkut的差异
    Google吸引用户有新招:Gmail中融合GTalk
    开发人员专用搜索引擎--Krugle
    Google桌面搜索新功能体验记(上) (中) (下)
    Google总部似乐园(图)

posted @ 2006-02-24 00:27 Flyingis 阅读(1356) | 评论 (4)编辑 收藏

WebGIS发布前GIS工程规划设计

    作者:Flyingis

    对于一个GIS系统来说,不论是桌面GIS还是WebGIS,最重要的和最有价值的是数据,没有设计良好的空间数据的支撑,该GIS系统就失去了其存在的意义。目前,主流的比较成熟的 WebGIS发布平台是ESRI的ArcIMS和MapInfo的MapXtreme,基于这两大平台均可以发布各自产品的数据,通过整合MIS功能,实现政务管理、管网管理等应用。在程序发布前,我们需要经过深加工的、可以满足用户业务需求的、完整的、可用于特定平台发布的GIS数据,这个前期的工作属于GIS工程的规划设计,一般可以分以下几个步骤完成:

    1. 确定项目要实现的目标,即GIS工程的开发目的。经常我们需要回答这些问题,什么是需要解决的问题?目前这个问题解决的怎么样了?这个工程的最终产品需要以什么样的形式展示,是报告,是高质量的可用于大幅展示的地图,是用 WebGIS 将产品发布,还是这些最终产品都需要?这个产品的用户群是谁?这些数据是否还要用于其他的用途?等等。这个步骤有点类似于软件工程的项目可行性报告和需求分析中的部分工作,但是更强调产品对数据的要求。

    2. 建立工程数据。这项工作的工作量一般情况下都非常大,除非项目经费充足可以购买数据或是手中已经有许多工作中需要的数据,否则需要三个步骤来完成,设计地理空间数据库,包括所需字段、字段类型等等,产品数字化和数据的整理,还有管理数据库,如设定坐标系、连接相邻图层。

    3. 分析数据。空间数据的分析是GIS工程的一项重要任务,分析的过程将直接影响最终的产品结果。空间数据分析包括计算距离、生成缓冲区、计算面积周长、覆盖数据值相同的区域、定位、路径选择等等。

    4. 成果展示。主要是展示数据分析的最终结果,以什么样的形式展现出来最好,或能满足用户需求,以WebGIS发布是其中的一种,另外还有图表和报告等形式。

    GIS软件工程的开发和计算机软件工程有很多相似之处,但其中最大的区别也是最重要的就是对数据有比较特殊的要求,因此在进行WebGIS平台开发部署之前,需要把握整个数据的概况,而了解整个GIS工程的规划设计对开发人员理解WebGIS构造和应用是极有帮助的,包括平台软件的使用和基础功能的应用等等。


posted @ 2006-02-15 11:41 Flyingis 阅读(1820) | 评论 (1)编辑 收藏

开发人员专用搜索引擎--Krugle

作者: Flyingis

    网络搜索领域从来没有停止过战争,可能是
Google 了解到自己的即时通讯聊天软件 GoogleTalk 的市场份额还远远不及传统 QQ/MSN/YAHOO IM 软件,因此准备在Gmail中嵌入“Gmail Chat”,靠目前

Gmail 的影响力来让用户了解和使用 Google 公司的 GoogleTalk

但对于开发人员来说,近期关于网络搜索的热点新闻肯定少不了 Krugle 一个为开发人员量身定做的开发引擎,它主要有以下几种功能:

1.        和传统搜索引擎不同, Krugle 专门用来搜索代码,不管是压缩包文件,还是展示在 blog 、网页上的代码,只要是在网络开放的空间内, Krugle 都能找到,并且 Krugle 还可以自动生成某个特定代码的 API 报告 ( 尚处实验阶段 )

2.        Krugle 能提供和代码相关问题的解答。

3.      允许开发人员对搜索结果进行评论,并通过创建 tag 的方式来帮助其他人更好的找到所需的代码,实现共享。

4.       Krugle 具有较快的搜索速度,能对和代码相关的例如各种技术主题、 API 、示例、文档进行快速搜索。

Krugle 的宣传如此,究竟其功能和性能如何现在还不知道,要等到 3 8 Krugle 搜索才会在San Diego的 O’Reilly Emerging Technology Conference 上亮相,现在可以在Krugle网站上注册 ,等到该搜索引擎 3 8 上线后, Krugle 会向用户的注册信箱发送 E-mail 来邀请体验 Krugle 搜索。和最初 Gmail/orkut/wallop需要邀请 一样,体验新鲜东西总是有些麻烦,不管怎么样,Krugle还是让人期待的。

附图链接: krugle搜索主页面    搜索代码    搜索解答    保存和共享

posted @ 2006-02-09 23:57 Flyingis 阅读(3050) | 评论 (3)编辑 收藏

基本数据结构的Java实现

链表

class Node {

Object item; Node next;

  Node (Object v) {

item = v; next = null;

}

}

头指针,空尾指针

初始化:head = null;

x后插入t

if ( x == null)

{ head = t; head.next = null; }

else { t.next = x.next; x.next = t; }

移走x之后的结点:t = x.next; x.next = t.next;

循环遍历:for ( t = head; t != null; t = t.next )

检查链表是否为空:if ( head == null )

空头结点,空尾指针

初始化:head = new Node(); head.next = null;

x后插入tt.next = x.next; x.next = t;

移走x之后的结点:t = x.next; x.next = t.next;

循环遍历:for ( t = head.next; t != null; t = t.next )

检查链表是否为空:if ( head.next == null )

空头结点,空尾结点

初始化:head = new Node(); z = new Node(); head.next = z; z.next = z;

x后插入tt.next = x.next; x.next = t;

移走x之后的结点:t = x.next; x.next = t.next;

循环遍历:for ( t = head.next; t != z; t = t.next )

检查链表是否为空:if ( head.next == z )

循环链表

第一次插入:head.next = head;

x后插入tt.next = x.next; x.next = t;

移走x之后的结点:t = x.next; x.next = t.next;

循环遍历:t = head; do { t = t.next; } while ( t != head );

检查是否只有一个数据项:if ( head.next == head )

 

堆栈

数组实现

class Stack {

  private Object[] s;

  private int n;

  Stack ( int maxN ) {

    s = new Object[maxN]; n = 0;

}

boolean isEmpty() { return ( n == 0 ); }

void push ( Object item ) { s[n++] = item; }

Object pop() {

  Object t = s[--n]; s[n] = null; return t;

}

}

链表实现

class Stack {

  private Node head;

  private class Node {

Object item; Node next;

Node ( Object item, Node next ) {

  this.item = item; this.next = next;

}

}

Stack ( Object maxN ) { head = null; }

boolean isEmpty() { return ( head ==null ); }

void push ( Object item ) { head = new Node(item, head); }

Object pop() {

  Object v = head.item;

  Node t = head.next;

  head = t;

  return v;

}

}

 

FIFO队列的链表实现

class Queue {

  private class Node {

Object item; Node next;

Node ( Object item ) {

  this.item = item; this.next = null;

}

}

Private Node head, tail;

Queue ( Object max ) { head = null; tail = null; }

boolean isEmpty() { return ( head ==null ); }

void put ( Object item ) {

  Node t = tail;

  tail = new Node(item);

  if ( empty() )

    head = tail;

  else t.next = tail

}

Object get() {

  Object v = head.item;

  Node t = head.next;

  head = t;

  return v;

}

}

posted @ 2006-02-05 23:08 Flyingis 阅读(1125) | 评论 (1)编辑 收藏

数据结构中避免数据项的重复

抽象数据类型(ADT)是一种只能通过接口访问的数据类型,它是字段与基于字段的操作所构成的集合。这里的接口不是interface,而是访问数据的途径,接口把数据的表示和操作方法的实现完全分离开来。两种最基本的ADT是堆栈和队列,并且根据我们的需要,可以构建更为复杂的ADT,例如可以对数据项进行计数,检查数据项是否存在重复等等。

在很多实际应用中,我们都不允许存在数据项重复的情况,需要对用户提交的重复数据进行合适的处理。让用户保证不提交重复的数据可以避免这种情况的发生,但显然这种方法并不实际,既然使用ADT就是为了给使用它的程序员提供简单明了的数据类型解决方案,那么我们就应该在ADT中来解决这个问题。以队列为例,一般可以通过两种策略来处理这个问题:

1.        放弃新输入的数据项:当最新放入队列中的数据项已经在队列中时,放弃当前输入的数据项。

2.        放弃旧的数据项,保存新输入的数据项:当最新放入队列中的数据项已经在队列中时,放弃已经存在于队列中的数据项,保存当前放入的数据项。

    对于第一种处理方式,在一种特殊的情况下,数据项存储的数据是0~N-1之间的整数,那么可以通过增加一个新的数组a[i]或链表来储存boolean类型数据,当队列中第i个位置上已经存在数据i(i<=N-1),设置a[i]=boolean,那么可以通过a[i]来判断数据i是否已经存在于队列中。第二种处理方式比第一种更为复杂一些,如果有必要,还可以让用户去选择采取哪种策略来避免重复的数据项。但不管怎么样,我们可以通过构建不同类型的ADT,并在ADT中实现某些我们所需要的功能,将能极大限度地保证数据结构和算法的灵活性与清晰的结构,使基于ADT的实现能满足各种不同的具体应用,并方便类的重构。

posted @ 2006-01-30 00:34 Flyingis 阅读(1127) | 评论 (2)编辑 收藏

理解数组和链表的最基本特性

作者:Flyingis

 

数组和链表是数据结构中老生常谈的问题,在指针或是引用这些概念出来之前,数组就能用来实现链表的功能。这里所说的链表指的就是用指针或对象的引用来设计的链表。

在实际的应用开发中,数组由于它天生的种种特性(参考Java容器分析数组》),更多的会被开发人员所想到用到,但所有的数据结构都有它特定的适用场合。众所周知,数组和链表最大的区别在于,使用数组能够快速访问数组中的每个元素,而使用链表可以方便的操纵每个数据项。下面通过两个很有趣的例子说明了它们各自的区别与优势。

虽然在JDKJava提供了List接口及其接口的实现(ArrayList/LinkedList)对链表数据结构提供了有力的支持,具体可以参考Java容器分析—List和Set但下面数学上关于Josephus问题的实现仅使用了自定义的最简单的链表结构。

/**

 * 根据命令行输入的N值,计算出所有小于N的素数

 * 是素数将数组元素值设为true,否则设为false

 */

class ArrayApp {

  public static void main(String[] args) {

int N = Integer.parseInt(args[0]);

boolean[] a = new boolean[N];

for (int i = 2; i < N; i++)

  a[i] = true;

for (int i = 2; i < N; i++)

  if (a[i] != false)

    for (int j = i; j*i < N; j++)

      a[i*j] = false;

for (int i = 2; i < N; j++)

  if (a[i])

    System.out.println(“” + i);

}

}

/**

 * N个有编号的小球围成一圈,每个M-1个就拿去一个小球,计算最后剩下的球的位置

 */

class LinkApp {

  static class Node {

int value;

Node next;

Node (int v) { v = value; }

}

public static void main(String[] args) {

  int N = Integer.parseInt(args[0]);

  int M = Integer.parseInt(args[1]);

  Node first = new Node(1);

  Node x = first;

  for (int i = 2; i <= N; i++)

    x = (x.next = new Node(i));

  x.next = first;

  while (x != x.next) {

    for (int i = 1; i < M; i++)

      x = x.next;

    x.next = x.next.next;

}

System.out.println(“最后剩下的小球:” + x.value);

}

}

posted @ 2006-01-24 23:42 Flyingis 阅读(2220) | 评论 (0)编辑 收藏

算法分析规则

作者:Flyingis

    算法作为实现计算机程序实现时解决问题的方法,在计算机应用领域发挥着举足轻重的作用。它研究的内容是解决问题的方法,而不是计算机程序的本身。一个优秀的算法可以运行在比较慢的计算机上,但一个劣质的算法在一台性能很强的计算机上也不一定能满足应用的需要,因此,在计算机程序设计中,算法设计往往处于核心地位。如何去设计一个适合特定应用的优秀算法是众多开发人员所关注的焦点,在算法设计时,需要了解算法设计的规则。

要想充分理解算法并有效地应用于实际问题,关键是对算法的分析。通常我们可以利用实验对比分析、数学方法来分析算法。实验对比分析很简单,两个算法相互比较,它们都能解决同一问题,在相同环境下,哪个算法的速度快我们一般就会认为这个算法性能更好。数学方法能将算法分析的更为细致,能在严密的逻辑推理基础上判断算法的优劣,但在完成实际项目过程中,我们很多时候都不能去做这种严密的论证与推断,因为我们不是在完成一道数学难题,也不是数学领域的专家,将大量的时间花费在公式的计算与证明上会导致整个项目进度缓慢、成本过高,因此,在算法设计中,我们往往采用能近似表达性能的方法来展示某个算法的性能指标。例如,计算机对n2n2+2n的响应速度,当n比较大的时候几乎一样没什么区别,我们便可直接认为后者算法的复杂度为n2。在分析算法时,隐藏细节的数学表示法成为大O记法,它可以帮助我们简化算法复杂度的许多细节,提取主要成分,这和遥感图像处理中的主成分分析思想相近。

基于算法复杂度简化表达的思想基础上,我们通常会对算法进行最坏情况分析和平均情况分析。对于一个给定的算法,如果能保证它的最坏情况下的性能依然不错当然很好,但是在某些情况下,程序的最坏情况算法的运行时间和实际情况的运行时间相差很大,在实际应用中我们几乎不会碰到最坏情况下的输入,那么此时进行最坏情况分析显得有些画蛇添足,特别是分析最坏情况算法会花费大量精力的时候。算法的平均情况分析可以帮助我们估计程序的性能,作为算法分析的基本指标之一,但是平均情况和实际情况仍然会有相差很大的时候,这时我们便可以使用随机法来尽量模拟现实中的情况,这样可以得到在严格的概率意义上的预测运行时间。另外,对于一个经典算法,我们没有必要再去对该算法进行改进,研究它的上界和下界,只需要了解该算法的特性,然后在合适的时候使用它。

最后,当一个程序变快和变慢,让计算机反映出来的时间差几乎不会让人产生感觉的时候,我们也没有必要去改进这个算法,例如程序进行1000次循环花费0.001秒,改进后为0.1秒,在实际应用中通常也只需要几千次循环,此时我们就没有必要去花时间来研究这个算法了,只要该算法能正确完成任务即可。

posted @ 2006-01-22 00:34 Flyingis 阅读(3352) | 评论 (9)编辑 收藏

wallop 和orkut 的差异

    作者:Flyingis

    博客在前几年就已经存在了,但博客人数的增长速度和现在相比相差一个数量级,从QQ/BBS/Blog/Wiki的发展都经历了一个从缓速发展到飞速发展的质的变化,这是之前人们所不会预料的。它们都抓住了人们生活中最普通的但又是潜在的需求,从而在互联网中站稳脚跟,丰富了人们的网络生活,成为网络经济增长的亮点。

   
walloporkut大家都不陌生,它们被称为社会软件,似乎要像众多互联网上的“前辈”一样,挑起网络流行的大旗,成为网络中的新星。它们的理论基础,是美国著名社会心理学家米尔格伦(Stanley Milgram)于20世纪60年代最先提出的“六度分隔法”(Six degrees of separation)。前段时间在blogjava上胡子鱼给了一份邀请,让我有机会试用了wallop和orkut。

    虽然wallop和orkut都基于相同的理论基础,但Microsoft和Google的产品还是有许多不同点:

1. wallop算是一个真正意义上的RIA(
Rich Internet Application),orkut则基于当前最流行的AJAX技术。
2. wallop的风格当然离不开微软的“最佳用户体验”,不论是Windows XP、Vistual Studio 2005还是年底即将发布Vista都是如此。orkut则沿用Google一贯的简约、明了。
3. wallop的个人信息很简单,而orkut则为用户信息提供了丰富的细致的分类,让大家更容易了解朋友的基本信息。
4. wallop通过导入rss feed,可以让朋友直接在wallop上查阅个人的blog,并具有简单的blog功能。orkut则没有。
5. wallop中和朋友的等级划分比较简单,通过point to me来显示两人之间的关系。在orkut上可以了解到对方较为详细的信息,并通过众多等级划分和属性归类,将网络中的每一个个体都能准确划分到相应类别。
6. wallop功能上还比较简单。orkut则继承了Google搜索良好的基因,并集成了社区、媒体、新闻等功能,让人感觉更为丰富。

    在细节上,wallop和orkut还有许多不同的地方,但它们都为我们展示了Internet又一个丰富的内涵与体验,让人与人之间的距离更近。wallop和orkut这类社会软件最终走向何方,是否会成熟,和“前辈”一样被广大用户所接受?我们拭目以待。

    附图(点击后面链接可浏览原图):wallop  orkut
    
    wallop.gif    orkut.gif

    ps. 现在手上还有一些wallop、orkut和gmail的邀请,需要的朋友可以留下信箱。orkut没有限制,gmail有几十个,wallop有十个(送出去了两个,似乎没有减少)。注意,gmail的信箱接收邀请我试过两次都没有收到,大学校园的信箱也没有用,据说126/163的国内信箱也不行,因此建议用hotmail/msn/yahoo的信箱,这三个即发即收,我试过的。

    wallop邀请有限,需要的朋友请尽量提供hotmail/msn/yahoo的信箱,如果没有接收到邀请,证明邀请已送完,需要一点时间向wallop申请更多的邀请再发送给大家,已申请上wallop的朋友可以发送邀请给其他的人,我也可以请其他申请上的朋友发给你们。

    orkut需要gmail才能接收邀请,因此需要orkut邀请的我会先发送gmail邀请到你们的信箱,然后再把你们的gmail信箱反馈给我。

posted @ 2006-01-17 22:52 Flyingis 阅读(3459) | 评论 (143)编辑 收藏

Hibernate的灵活与方便

    作者:Flyingis

    许多软件设计的思维都源于生活的方方面面,可能存在某些设计思想并非受平时生活所启迪,但它们面临的情况却如此相象。软件设计原本就是生活的一部分,软件设计的“灵活”与“方便”(或“简便”)即是世界万物的一个共同点。

    Hibernate作为流行的企业应用和关系数据库之间的持久化中间件,受到越来越多的关注。虽然使用Hibernate可以使得项目易于维护,帮助开发人员更好地处理复杂关系模型,提供了很强的方便性,但却失去了JDBC原有的灵活性。如何在“灵活”与“方便”之间取舍、平衡显得重要起来。

    不久前江南白衣的一篇文章ORM透明持久化方案面对的共同困境道出了现在ORM不尽如人意的地方,除了网上,还有书本的前言等对Hibernate的众多赞美之词外,现在讨论它呆板、配置繁琐的声音也逐渐多了起来,最热闹的就是前段时间Ruby on Rails引起J2EE阵营的骚动。个人对Java研究尚浅,对Hibernate有一些使用心得,下面所列出的不一定是Hibernate本身的缺陷,不足之处希望大家拍砖指出。

1.  提取表单中字典Value的不便。
    字典一般由ID和NAME两个字段组成,其ID号存储于数据库其他表中,当查询这些表信息时,Hibernate以List或Set形式返回的结果,没有办法将ID号显示为对应的NAME。在JDBC中,可以直接通过Map来存储字典,通过map.getValue()来返回字典的值。

2.  Hibernate内置映射类型复杂化
    在开发过程中,时常会查找Hibernate映射类型--Java类型--标准SQL类型之间的关系。繁杂之处体现在两方面,一是各种数据库的数据类型和标准SQL之间会有一定的出入,二是Hibernate映射类型虽然大部分和Java类型相同,但也存在比较晦涩的地方,例如character类型对应Java的char / java.lang.Character / java.lang.String,text对应着Java的java.lang.String。

3.  ID规定化生成
    Hibernate中内置标识符生成器给表单ID自动生成提供了方便,但却不能自定义各种ID形式。开发过程中,有时需要特定的ID号来区分各种字典,例如字典1的ID号为1A,2A……,字典2的ID号为1B,2B……,当这些ID号存储在表单中时,可以方便开发人员在数据库中查找各表单存储各类字典数据的情况,方便调试,但使用Hibernate生成器就失去了这种灵活性。

    Hibernate的不足网上已有很多讨论,以上只是个人增加的几点体会。即使这样,Hibernate仍是一款优秀的持久层插件,只是“灵活”的背后隐藏着“复杂”,“方便”的背后隐藏着“不便”,如何取舍与平衡,还是看实际需要吧。

posted @ 2006-01-14 10:22 Flyingis 阅读(2722) | 评论 (5)编辑 收藏

GIS应用与开发中的网络模型

作者:Flyingis
   
    网络是用于实现资源的运输和信息的交流的相互连接的线性特征。网络模型是对现实世界网络的抽象。在模型中,网络由
Link Node Stop Center 组成。网络模型的典型的例子就是研究交通以及通过管线与隧道分析水、汽油、电力的流动。

网络组成要素简要说明

Link: 表示用于实现运输和交流的相互连接的线实体。如我们生活中的高速公路、铁路。

Node: Link 一定是在 Node 处相交,但相交的 Link 处不一定是 Node ,例如城市立交桥并没有相交,但是网络几何显示时却是相交的。

Stop: 在某个 Link 上经过的位置,如城市点、交通车站等。

Center: 指网络中一些离散位置,代表着现实世界里资源中心、购物中心,交通运输中心等。

常用的网络模型

1.        网络追踪

研究网络中资源和信息Link的流向。吉林石化爆炸造成松花江水域大面积污染,应用网络追踪即可分析从污染源开始,沿江流向下扩散的过程。网络追踪里涉及的一个重要概念是“连通性”,这决定了资源与信息在网络中的流动与走向。

2.        路径选择

路径选择即最佳Link路径选择,如经典的 Dijkstra 最短路径算法,在 GIS 应用中,物资输送、电力网络、行车路线等都涉及到这个问题,更为复杂的是,需要在这个过程中考虑许多影响流向通过的因素,例如交通中的红绿灯、堵塞情况,宽带网络中流量高峰期与低谷期。

3.        资源分配

反映显示世界网络中资源供需关系的模型。“供”一般位于 Center 位置,对空间中一个或多个点提供资源分配。这个分配范围有多大,分配距离有多远,分配的阻力有多强,是否有足够的物资信息等供分配,是这个模型需要研究的内容。

4.        空间相互作用和引力模型

用于理解和预测某点发生的活动和人、资源及信息的流动。通常情况下,两Stop点间距离越近,发生相互作用的可能性越大,但实际情况却不仅如此。

    在现在主流 GIS 应用软件中,例如 ArcGIS 已经提供了部分网络模型,如最常见的网络追踪模型,但模型的适用性和易用性并不完善,要满足实际应用要求,还需要在已有的模型基础上进行设计与二次开发。

Greenvalley.jpg

posted @ 2006-01-11 20:18 Flyingis 阅读(1689) | 评论 (1)编辑 收藏

软件整合--硬件整合--平台整合

    作者:Flyingis 

    “合久必分,分久必合”,不知道这句话最初是出自哪里?大概的意思应该是一个轮回的结束,代表的另一个轮回的开始。记得2004年考研的英语看图作文就是一位runner冲过终点线,在线的内侧写的是End,另一侧是Begin,这里面的含义很简单,在我们的生活中比比皆是。在IT行业,最近几年流行的是整合,软件整合、硬件整合与平台整合。

    软件整合
    Windows平台算是最典型的代表了,微软靠Windows整合了IE逐步吞噬了Netscape的市场,靠着Windows和Office / SQLServer / IIS / MediaPlayer最佳的兼容性,在各自的市场上都站稳了脚跟,有的甚至达到了一种垄断的局面,即使是最基本的记事本、游戏(扫雷、扑克牌之类的)、计算器等也成为了Windows使用者时常使用的软件。在开发平台上,微软也从来没有停止过脚步,最近的Visual Studio 2005 .Net让众多开发者望眼欲穿,其功能之强、操作之方便源于微软的强大实力,但最显著的特点就是整合了大多数软件开发中会使用到的应用工具,微软似乎像重新导演Windows当年的历史,靠整合不费吹灰之力打败那些倚着Windows(包括应用软件和开发软件)吃饭的小公司。
    除了微软之外,许多公司也进行着类似的整合,只是领域不同,应用范围不同,不管怎么样,微软总是会作为典型代表来分析讨论。Google公司是近年来IT领域的热点之一,也是让微软感觉不爽的公司之一,Google最近动作频频,特别是在搜索涉及的领域让微软防不胜防,虽然前段时间Bill Gates公开表示
公司的头号劲敌是IBM而不是Google,但Google让微软越来越紧张却是不争的事实,如果要故意挑他的语病,不是头号劲敌,那就是第二号或第三号吧,本来和IBM相比,Google还是欠些火候,但按照Google现在的发展趋势,谁也不敢小视。刚到2006年,Google就推出了一项新的下载服务:Google一体化软件服务--Google Pack。Google Pack是Google提供的面向Windows平台的一系列软件的集合,目的是方便快捷地为用户的电脑提供合适的基本软件。这又是一种软件整合。

    硬件整合
    硬件整合里面最耀眼的非Intel的迅驰莫属。Intel靠迅驰一代(三大件的整合CPU/芯片组/无线网卡)就在民用笔记本市场占领了大半的份额,受到了众多的好评,当然,也直接为Intel带来了丰厚的利润。迅驰二代Sonoma平台的虽然颇有争议,但凭借Intel强大的市场运作能力、产品推广速度和一代产品创造的良好根基,还是继承了迅驰一代的市场地位,并开始逐步过渡到迅驰三Napa。不论是哪一个时期的迅驰都吸引了全世界的眼球,Intel迅驰三Napa的发布也预示着Intel要将这个平台挖掘到底,甚至在台式机市场也要适时推出类似的硬件整合平台,将整合带来的利润最大化。家庭娱乐平台Intel VIIV已经推出,虽然其经济效应和规模效应都还不如迅驰,但总是让人充满期待。

    平台整合
    信息专家们和分析师们预言将来的数据中心将是多种操作系统共存的情况,包括Windows和各种各样的Unix变体。除此之外,还应该包括多种数据库、应用软件之间的无缝集成,这对各个系统的可靠性、弹性、可扩展性和交互性提出了更高的要求。.NET和J2EE的互用性问题非常重要,是因为大多数企业都在使用其中之一或同时使用这两种平台来开发程序,用Web Services来整合.NET和J2EE是不同软件开发平台之间的整合,它为两种平台之间的整合提供了一种解决方案。数据管理与应用集成解决方案供应商Sybase与Linux领域的Turbolinux共同打造的企业级数据管理平台,即整合了双方各自在数据库、操作系统平台的领先优势,将各自的旗舰产品捆绑成一个极具竞争力的企业级数据管理平台。这是数据库和应用软件之间的整合。因此,平台整合代表了应用性能的增强,开发集成的便利与应用开销成本的最小化,这也是IT领域的发展趋势之一。

    软件整合--硬件整合--平台整合代表了未来,至少未来这些年IT领域的发展方向,当然也代表行业垄断的趋势。除去政治上的各种因素,这些整合对于技术应用与发展来说,无疑是一种好的趋势。“分久必合,合久必分”,只是,后面的一句话会像前面一句一样,在今后的某一段时期,在IT行业繁荣起来吗?可能吗?

posted @ 2006-01-09 13:30 Flyingis 阅读(1175) | 评论 (0)编辑 收藏

Java I/O中的对象序列化

作者:Flyingis

      Java对象序列化将那些实现了Serializable接口的对象转换成一个字节序列,并能够以后将这个字节序列完全恢复为原来的对象。利用对象的序列化,可以实现轻量级持久性,这意味着一个对象的生存周期并不取决于程序是否正在执行,它可以生存于程序的调用之间。通过将一个序列化对象写入磁盘,然后在重新调用程序时恢复该对象,就能够实现持久性的效果。JDOHibernate等中间件为我们提供了更规范、完善的持久化机制,这里所述只是最基本的基于文件I/O的持久化。

对象序列化主要是为了支持两种主要的特性,一是Java远程方法调用(RMI),另外一个是序列化Java Beans

1.        实现了Serializable接口的对象的序列化

要序列化一个对象,首先要创建OutputStream对象,然后将其封装在一个ObjectOutputStream对象内。此时,调用writeObject()方法将对象序列化并发送给OutputStream。在反序列化时,需要将一个InputStream封装在ObjectInputStream内,然后调用readObject(),得到的结果是一个Object对象,需要进行转型得到最后所需的对象。需要注意的是,在对一个Serializable对象进行反序列化的过程中,没有调用任何构造器,包括缺省的构造器,整个对象都是通过从InputStream中取得数据恢复过来的。对象序列化是面向字节的,因此采用InputStreamOutputStream层次结构。

2.        实现了Externalizable接口的对象的序列化

Externalizable接口继承了Serializable接口,同时添加了writeExternal()readExternal(),它们在序列化和反序列化过程中会被自动调用。出于安全的考虑,可以将需要序列化的对象在上述方法中显式处理,否则不用在上述两个方法内考虑。注意,对于实现了Serializable接口的对象,对象完全以它存储的二进制位为基础来构造,不调用构造器。而对于一个Externalizable对象,所有普通的缺省构造器都会被调用,然后调用readExternal()

3.        transient关键字

在某些情况下,有些特定的子对象不希望Java序列化机制自动保存与恢复,即使对象中的这些信息是private的,经过序列化处理,就可以通过读取文件或者拦截网络传输的方式来访问到它。实现了Externalizable接口的对象的writeExternal()方法可以对需要的对象进行显式的序列化,但是如果我们操作的是一个实现了Serializable接口的对象,就只能用transient关键字逐个字段的关闭序列化,只需要在字段定义前加上该关键字即可。

4.        实现了Serializable接口的同时,提供两个方法

private void writeObject(ObjectOutputStream stream) throws IOException

private void readObject(ObjectInputStream stream)

throws IOException, ClassNotFoundException

这种方法使用起来比较混乱,仅仅提供了这样的一种功能,绝大多数情况下,使用前面三种方法就能满足需求。

posted @ 2006-01-08 13:13 Flyingis 阅读(2624) | 评论 (5)编辑 收藏

文件加锁基础

作者:Flyingis

    文件加锁是
JDK1.4引入的一种机制,它允许我们同步访问某个作为共享资源的文件。竞争同一文件的两个线程可能在不同的Java虚拟机上,或者一个是Java线程,另一个是操作系统中的某个本地线程。文件锁对其他的操作系统进程是可见的,因为Java的文件加锁直接映射到了本地操作系统的加锁工具。

通过对FileChannel调用tryLock()lock(),就可以获得整个文件的FileLock。特殊的是,SocketChannel/DatagramChannel/ServerSocketChannel不需要加锁,因为它们是从单进程实体继承而来,我们通常不在两个进程之间共享网络的socket

tryLock()是非阻塞式的,它设法获取锁,但如果不能获得,例如因为其他一些进程已经持有相同的锁,而且不共享时,它将直接从方法调用返回。

lock()是阻塞式的,它要阻塞进程直到锁可以获得,或调用lock()的线程中断,或调用lock()的通道关闭。

对独占锁和共享锁的支持必须由底层的操作系统提供。锁的类型可以通过FileLock.isShared()进行查询。另外,我们不能获取缓冲器上的锁,只能是通道上的。

文件加锁的实际应用之一:文件映射通常应用于大型的文件,我们可能需要对巨大的文件进行部分加锁,以便其他的进程可以修改文件中未被加锁的部分,数据库就是如此,使得多用户可以访问到未加锁的部分数据。其他的应用还知之甚少。

posted @ 2006-01-07 13:50 Flyingis 阅读(3914) | 评论 (2)编辑 收藏

2006年的 Java IDE

    作者: Flyingis

    随着Eclipse影响逐步扩大,IDE市场热闹非凡,不论是老牌Borland的JBuilder还是NetBeans,还有Sun免费的Java Studio Creator似乎都想在这个市场上拼出一条血路,记住!不要忘了可爱的IntelliJ!

    看着微软强大的Visual Studio系列产品,Java始终都想拥有一款可以相媲美的IDE,现在开源的Eclipse做的算是不错了,拥有丰富的插件支持,但Eclipse经常莫名其妙crashes估计谁的碰到过,在以前JBuilder7/8年代,中文光标的问题也需要修改一个文件才能解决(现在没有使用,不知道是否仍然存在),世上总是没有完美。也许最原始的EditPlus+JDK才是一种优雅简单的解决方案。下面,看看这些Java IDE新闻大杂烩吧,看看2006年的Java IDE会拼出什么火花。

    NetBeans VS Eclipse,新一轮的争端
    Matisse和NetBeans 弄潮下一波GUI设计
    Eclipse 3.2 M4 加入Swing 和IntelliJ IDEA 新功能
    凤凰浴火:JBuilder 2006新功能赏析

posted @ 2006-01-05 20:51 Flyingis 阅读(2348) | 评论 (3)编辑 收藏

Java I/O中的数据编码转换

作者:Flyingis

      JDK1.4
开始便引入了java.nio.*包,其目的在于提高I/O的速度,这是因为该类库使用的结构更接近于操作系统执行I/O的方式,即通过通道和缓冲器来读写数据。在实际应用中,和我们直接交互的是缓冲器,然后把缓冲器派送到通道,通道要么从缓冲器获得数据,要么向缓冲器发送数据。


    在基于
Java的各种开发中,字符编码是常见的问题之一,在最基本的Java I/O中也存在这种问题。新的Java I/O通过通道和缓冲器来读写数据,缓冲器容纳的是普通的字节,为了把它们转换成字符,我们要么在输入的时候对其进行编码,要么在从缓冲器输出时对它们进行解码。


import java.io.*;

import java.nio.*;

import java.nio.channels.*;

import java.nio.charset.*;

public class ByteToCharacter {

  private static final int SIZE = 1024;

  public static void main(String[] args) throws Exception {

FileChannel fc = new FileOutputStream(“Output.txt”).getChannel();

ByteBuffer buffer = ByteBuffer.allocate(SIZE);

/**

* 在输入的时候进行编码方式一

*/

fc.write(ByteBuffer.wrap(“Good holiday!”.getBytes(“UTF-16BE”)));  // UTF-16BE可以更换为其他编码方式

fc.close();

fc = new FileInputStream(“Output.txt”).getChannel();

fc.read(buffer);

buffer.flip();  //准备从缓冲区读取已经写入的数据

System.out.println(buffer.asCharBuffer());

/**

* 在输入的时候进行编码方式二

* 通过asCharBuffer()方法直接以char形式将字符写入

*/

fc = new FileOutputStream(“Output.txt”).getChannel();

buffer.clear();

buffer.asCharBuffer.put(“Good holiday has passed!”);

fc.write(buffer);

fc.close();

fc = new FileInputStream(“Output.txt”).getChannel();

buffer.clear();

fc.read(buffer);

buffer.flip();

System.out.println(buffer.asCharBuffer());

/**

* 从缓冲器输出时进行编码

*/

fc = new FileOutputStream(“Output.txt”).getChannel();

fc.write(ByteBuffer.wrap(“Once again!”.getBytes()));

fc.close();

fc = new FileInputStream(“Output.txt”).getChannel();

buffer.clear();

fc.read(buffer);

buffer.flip();

String encode = System.getProperty(“file.encoding”);  // 平台缺省字符集,更加通用的方法,跨平台特性的体现之一

System.out.println(Charset.forName(encode).decode(buffer));

}

}


   
在上述代码中,如果不对从缓冲器写入的数据进行正确编码,那么当再次通过缓冲器读取这些数据时,将不能显示任何所需要的数据。


    JDK
中的java.nio.charset.Charset类提供了把数据编码成多种不同类型的字符集的工具,满足在各种应用中的编码需求。

posted @ 2006-01-03 14:02 Flyingis 阅读(1431) | 评论 (0)编辑 收藏

Java I/O中的设计模式

作者:Flyingis

    任何程序语言的
I/O设计都是一项具有挑战的任务,因为数据的传输存在多种可能,这些可能不仅存在于数据发送端和接收端(文件、网络链接等),还存在于这些数据的多种存在方式,例如缓冲区数据、顺序存取数据、字符数据、字节数据等等。

JavaI/O使用“流”这个抽象的概念,它屏蔽了实际的I/O设备中处理数据的细节。在实际的应用中,我们很少使用单一的类来创建流对象,而是通过多个对象来提供所需要的I/O功能。Java1.01.11.4I/O类库作了多次重大修改,具体的可以参考相关的书籍或Sun官方网站。这里是从模式的角度来分析JavaI/O类库的设计。

Strategy设计模式

将会发生变化的代码封装在单独的类(Strategy对象)中,供其他保持不变的类使用,实现某种算法或应用,这是Strategy设计模式的一般思想。在Java I/O中,一个典型的应用是File类,它可以代表一个特定文件的名称,也可以代表一个目录下一组文件的名称。当我们要查询显示一个目录下特定文件类型的所有文件对象信息时,就需要将这个目录下的文件过滤,找到所需要的对象。

import java.io.*;

import java.util.*;

import java.util.regex.*;

 

public class AlphabeticComparator implements Comparator {

public int compare(Object o1, Object o2) {

  String s1 = (String)o1;

  String s2 = (String)o2;

  return s1.toLowerCase().compareTo(s2.toLowerCase());  //比较时不考虑大小写

}

}

 

public class FruitList {

  public static FilenameFilter filter(final String regex) {

return new FilenameFilter() {

  private Pattern pattern = Pattern.compile(regex);

  public boolean accept(File dir, String name) {

    return pattern.matcher(new File(name).getName()).matches();

}

};

}

public static void main(String[] args) {

  File path = new File(“.”);

  String[] list;

  if (args.length == 0)

    list = path.list();  //搜索出该目录下所有类型的文件

else

  list = path.list(filter(args[0]));  //搜索出该目录下指定类型的文件

Arrays.sort(list, new AlphabeticComparator());

for (int i = 0; i < list.length; i++)

  System.out.println(list[i]);

}

}在上述代码中,有两个地方使用了Strategy设计模式,一个是AlphabeticComparator类,用来在忽略字符串大小写的情况下提供排序的规则,另一个就是FilenameFilter接口,使用了匿名内部类的设计,然后将其中实现的accept()规则提供给File类的list方法使用。这里是用来判断正则表达式regex是否和文件名匹配,当运行程序在命令操作符中输入“E.*\.java”时,搜索到的是该目录下所有.java文件。

File类除了上述用法外,还可以创建或删除目录,查看文件的信息,包括文件大小、最后修改日期,读写状态等,具体的可以参考JDK文档。

Decorator设计模式

http://www.j2eesp.com上有对Decorator设计模式的定义:动态给一个对象添加一些额外的职责,就像在墙上刷油漆。使用Decorator模式相比用生成子类方式达到功能的扩充显得更为灵活。Decorator模式规定所有封装于初始对象内部的对象具有相同的接口,这使得该模式的应用具有透明性。

Java I/O设计中,Decorator模式主要体现在filter类的设计上,抽象类filter是所有Decorator模式类的基类。但是Decorator模式同样存在缺点:在编写程序时,它在给开发人员提供了灵活性的同时,增加了代码的复杂性,造成了Java I/O类操作不便,因为很多I/O设计中都需要应用Decorator模式,增加一些类来完成该设计。

例如在Java 1.0中,FilterInputStreamInputStream中读取数据,FilterOutPutStreamOutputStream中写入数据,在Java 1.1中,相应的有FilterReaderFilterWriter(抽象类,没有子类)用于Decorator模式设计。举个简单的例子:

import java.io.*;

public class DecoratorDemo {

  public static void main(String[] args) {

BufferedReader in = new BufferedReader(new FileReader(“FruitList.java”));

String s = new String();

while ((s = in.readLine()) != null)

  System.out.println(s);

in.close();

}

}

    BufferedReaderFileReader完成了Decorate模式设计,这两个类可以更换为其他具有相同功用的类(在Thinking in Java中称为“修饰器”类)来组合完成特定的任务,正如上文所述,这给开发者提供了多种组合方式,同时也相对的增加了复杂度。

    最后,祝blogjava所有成员和Java、开源爱好者元旦快乐!幸福安康!

posted @ 2005-12-30 21:47 Flyingis 阅读(2577) | 评论 (4)编辑 收藏

测试你电脑功率的大小

    这个网站可以测试你电脑的大概功率,当然,这个功率是所有部件都处于高负荷运行时的功率,可以作为参考。另外,笔记本的部件不在测试之列,如果台式机过于先进(例如显卡是Nvidia Geforce 7800 GTX)也不能找到相关的部件选项。
    测试链接:http://www.jscustompcs.com/power_supply/

    进入网站后,需要选择电脑的CPU类型是AMD还是Intel,或者你要测试的是服务器,进入页面后再选择电脑的各个部件即可。有空可以看看,纯属无聊消遣!

TestYourComputer.gif

posted @ 2005-12-28 15:38 Flyingis 阅读(5346) | 评论 (3)编辑 收藏

SOA介绍--什么是SOA?[转载]

版权声明:本文可以自由转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
作者:Raghu R. Kodali  翻译:
tetsu(译者的Blog:http://blog.matrix.org.cn/page/tetsu)
原文:
http://www.javaworld.com/javaworld/jw-06-2005/jw-0613-soa.html
中文:http://www.matrix.org.cn/resource/article/44/44070_SOA.html
关键字:SOA

摘要
在最近的软件发展中,面向服务架构(SOA, service-oriented architecture)成为了时下的热门话题。这篇文章将向大家介绍SOA, 讨论企业为什么需要SOA,什么是SOA, 从核心,平台,服务品质3个层面来解释SOA的基础构成。
By Raghu R. Kodali



对于面向同步和异步应用的,基于请求/响应模式的分布式计算来说,SOA是一场革命。一个应用程序的业务逻辑(business logic)或某些单独的功能被模块化并作为服务呈现给消费者或客户端。这些服务的关键是他们的松耦合特性。例如,服务的接口和实现相独立。应用开发人员或者系统集成者可以通过组合一个或多个服务来构建应用,而无须理解服务的底层实现。举例来说,一个服务可以用.NET或J2EE来实现,而使用该服务的应用程序可以在不同的平台之上,使用的语言也可以不同。

SOA有以下特性
        SOA服务具有平台独立的自我描述XML文档。Web服务描述语言(WSDL, Web Services Description Language)是用于描述服务的标准语言。
        SOA 服务用消息进行通信,该消息通常使用XML Schema来定义(也叫做XSD, XML Schema Definition)。消费者和提供者或消费者和服务之间的通信多见于不知道提供者的环境中。服务间的通讯也可以看作企业内部处理的关键商业文档。
         在一个企业内部,SOA服务通过一个扮演目录列表(directory listing)角色的登记处(Registry)来进行维护。应用程序在登记处(Registry)寻找并调用某项服务。统一描述,定义和集成 (UDDI, Universal Description, Definition, and Integration)是服务登记的标准。
         每项SOA服务都有一个与之相关的服务品质(QoS, quality of service)。QoS的一些关键元素有安全需求(例如认证和授权),可靠通信(译注:可靠消息是指,确保消息“仅且仅仅”发送一次,从而过滤重复信息。),以及谁能调用服务的策略。

为什么选择SOA?

不同种类的操作系统,应用软件,系统软件和应用基础结构(application infrastructure)相互交织,这便是IT企业的现状。一些现存的应用程序被用来处理当前的业务流程(business processes),因此从头建立一个新的基础环境是不可能的。企业应该能对业务的变化做出快速的反应,利用对现有的应用程序和应用基础结构(application infrastructure)的投资来解决新的业务需求,为客户,商业伙伴以及供应商提供新的互动渠道,并呈现一个可以支持有机业务(organic business)的构架。SOA凭借其松耦合的特性,使得企业可以按照模块化的方式来添加新服务或更新现有服务,以解决新的业务需要,提供选择从而可以通过不同的渠道提供服务,并可以把企业现有的或已有的应用作为服务, 从而保护了现有的IT基础建设投资。

如图1的例子所示,一个使用SOA的企业,可以使用一组现有的应用来创建一个供应链复合应用(supply chain composite application),这些现有的应用通过标准接口来提供功能。

image
Figure 1. Supply chain application. Click on thumbnail to view full-sized image.         


服务架构

为了实现SOA,企业需要一个服务架构,图2显示了一个例子:

image
Figure 2. A sample service architecture. Click on thumbnail to view full-sized image.        

在图2中, 服务消费者(service consumer)可以通过发送消息来调用服务。这些消息由一个服务总线(service bus)转换后发送给适当的服务实现。这种服务架构可以提供一个业务规则引擎(business rules engine),该引擎容许业务规则被合并在一个服务里或多个服务里。这种架构也提供了一个服务管理基础(service management infrastructure),用来管理服务,类似审核,列表(billing),日志等功能。此外,该架构给企业提供了灵活的业务流程,更好地处理控制请求(regulatory requirement),例如Sarbanes Oxley(SOX),并且可以在不影响其他服务的情况下更改某项服务。

SOA基础结构

要运行,管理SOA应用程序,企业需要SOA基础,这是SOA平台的一个部分。SOA基础必须支持所有的相关标准,和需要的运行时容器。图3所示的是一个典型的SOA基础结构。接下来的章节将逐一讨论该结构的每个部分。

image
Figure 3. A typical SOA infrastructure. Click on thumbnail to view full-sized image.         

SOAP, WSDL, UDDI
WSDL, UDDI和SOAP是SOA基础的基础部件。WSDL用来描述服务;UDDI用来注册和查找服务;而SOAP,作为传输层,用来在消费者和服务提供者之间传送消息。SOAP是Web服务的默认机制,其他的技术为可以服务实现其他类型的绑定。一个消费者可以在UDDI注册表(registry)查找服务,取得服务的WSDL描述,然后通过SOAP来调用服务。

WS-I Basic Profile
WS-I Basic Profile,由Web服务互用性组织(Web Services Interoperability Organization)提供,是SOA服务测试与互用性所需要的核心构件。服务提供者可以使用Basic Profile测试程序来测试服务在不同平台和技术上的互用性。

J2EE 和 .Net
尽管J2EE和.NET平台是开发SOA应用程序常用的平台,但SOA不仅限于此。像J2EE这类平台,不仅为开发者自然而然地参与到SOA中来提供了一个平台,还通过他们内在的特性,将可扩展性,可靠性,可用性以及性能引入了SOA世界。新的规范,例如 JAXB(Java API for XML Binding),用于将XML文档定位到Java类;JAXR(Java API for XML Registry)用来规范对UDDI注册表(registry)的操作;XML-RPC(Java API for XML-based Remote Procedure Call)在J2EE1.4中用来调用远程服务,这使得开发和部署可移植于标准J2EE容器的Web服务变得容易,与此同时,实现了跨平台(如.NET)的服务互用。

服务品质
在企业中,关键任务系统(mission-critical system,译注:关键任务系统是指如果一个系统的可靠性对于一个组织是至关重要的,那么该系统就是该企业的关键任务系统。比如,电话系统对于一个电话促销企业来说就是关键任务系统,而文字处理系统就不那么关键了。)用来解决高级需求,例如安全性,可靠性,事物。当一个企业开始采用服务架构作为工具来进行开发和部署应用的时候,基本的Web服务规范,像WSDL,SOAP,以及UDDI就不能满足这些高级需求。正如前面所提到的,这些需求也称作服务品质(QoS,quality of services)。与QoS相关的众多规范已经由一些标准化组织(standards bodies)提出,像W3C(World Wide Web Consortium)和OASIS(the Organization for the Advancement of Structured Information Standards)。下面的部分将会讨论一些QoS服务和相关标准。

安全
Web服务安全规范用来保证消息的安全性。该规范主要包括认证交换, 消息完整性和消息保密。该规范吸引人的地方在于它借助现有的安全标准,例如,SAML(as Security Assertion Markup Language)来实现web服务消息的安全。OASIS正致力于Web服务安全规范的制定。

可靠
在典型的SOA 环境中,服务消费者和服务提供者之间会有几种不同的文档在进行交换。具有诸如“仅且仅仅传送一次”( once-and-only-once delivery),“最多传送一次”( at-most-once delivery),“重复消息过滤”(duplicate message elimination),“保证消息传送”(guaranteed message delivery)等特性消息的发送和确认,在关键任务系统(mission-critical systems)中变得十分重要。WS-Reliability 和 WS-ReliableMessaging是两个用来解决此类问题的标准。这些标准现在都由OASIS负责。

策略
服务提供者有时候会要求服务消费者与某种策略通信。比如,服务提供商可能会要求消费者提供Kerberos安全标示,才能取得某项服务。这些要求被定义为策略断言(policy assertions)。一项策略可能会包含多个断言。WS-Policy用来标准化服务消费者和服务提供者之间的策略通信。

控制
当企业着手于服务架构时,服务可以用来整合数据仓库(silos of data),应用程序,以及组件。整合应用意味着例如异步通信,并行处理,数据转换,以及校正等进程请求必须被标准化。在SOA中,进程是使用一组离散的服务创建的。BPEL4WS 或者 WSBPEL(Web Service Business Process Execution Language)是用来控制这些服务的语言。WSBPEL目前也由OASIS负责。

管理
随着企业服务的增长,所使用的服务和业务进程的数量也随之增加,一个用来让系统管理员管理所有运行在多相环境下的服务的管理系统就显得尤为重要。WSDM(Web Services for Distributed Management)规定了任何根据WSDM实现的服务都可以由一个WSDM适应(WSDM-compliant)的管理方案来管理。

其它的qos特性,比如合作方之間的溝通和通訊,多個服務之間的事務處理,都在WS-Coordination 和 WS-Transaction 標準中描述, 這些都是OASIS 的工作.

SOA 不是Web服务
在理解SOA和Web服务的关系上,经常发生混淆。根据2003年4月的Gartner报道,Yefim V. Natis就这个问题是这样解释的:“Web服务是技术规范,而SOA是设计原则。特别是Web服务中的WSDL,是一个SOA配套的接口定义标准:这是 Web服务和SOA的根本联系。”从本质上来说,SOA是一种架构模式,而Web服务是利用一组标准实现的服务。Web服务是实现SOA的方式之一。用 Web服务来实现SOA的好处是你可以实现一个中立平台,来获得服务,而且随着越来越多的软件商支持越来越多的Web服务规范,你会取得更好的通用性。

SOA的优势

SOA 的概念并非什么新东西,SOA不同于现有的分布式技术之处在于大多数软件商接受它并有可以实现SOA的平台或应用程序。SOA伴随着无处不在的标准,为企业的现有资产或投资带来了更好的重用性。SOA能够在最新的和现有的应用之上创建应用;SOA能够使客户或服务消费者免予服务实现的改变所带来的影响; SOA能够升级单个服务或服务消费者而无需重写整个应用,也无需保留已经不再适用于新需求的现有系统。总而言之,SOA以借助现有的应用来组合产生新服务的敏捷方式,提供给企业更好的灵活性来构建应用程序和业务流程。

About the author
Raghu R. Kodali is consulting product manager and SOA evangelist for Oracle Application Server. Kodali leads next-generation SOA initiatives and J2EE feature sets for Oracle Application Server, with particular expertise in EJB, J2EE deployment, Web services, and BPEL. Prior to product management, Kodali held presales and technical marketing positions in Oracle Asia-Pacific, based in Singapore. Prior to Oracle, he worked as software developer with National Computer Systems, Singapore. He holds a master's degree in computer science and is a frequent speaker at technology conferences. Kodali maintains an active blog at Loosely Coupled Corner

资源
·
Java开发者社区:http://www.matrix.org.cn
·javaworld.com:javaworld.com
WS-I: http://www.ws-i.org
JAXB: http://www.java.sun.com/xml/jaxb
JAXR: http://java.sun.com/xml/jaxr
OASIS: http://www.oasis-open.org/home/index.php
SAML: http://www.oasis-open.org/specs/index.php#samlv1.0
SOAP: http://www.w3.org/TR/soap/
SOX: http://www.sarbanes-oxley.com/
UDDI: http://www.uddi.org/specification.html
W3C: http://www.w3.org/2002/ws/
WSDL: http://www.w3.org/TR/wsdl
WSBPEL: http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=wsbpel
WS-Reliability: http://www.oasis-open.org/specs/index.php#wsrv1.1
WS-ReliableMessaging: http://xml.coverpages.org/WS-ReliableMessaging200502.pdf
Web Services Security: http://www.oasis-open.org/specs/index.php#wssv1.0
WS-I Basic Profile:http://www.ws-i.org/deliverables/workinggroup.aspx?wg=basicprofile
WSDM: http://www.oasis-open.org/committees/tc_home.php
XSD: http://www.w3.org/XML/Schema
Gartner: http://www.gartner.com/Init
To read about BEA's recent product offering in the SOA space, read "BEA's Patrick Discusses Project Free Flow," Paul Krill, InfoWorld (JavaWorld, June 2005): http://www.javaworld.com/javaworld/jw-06-2005/jw-0613-iw-bea.html
For more on SOA, read "Event-Driven Services in SOA," Jeff Hanson (JavaWorld, January 2005): http://www.javaworld.com/javaworld/jw-01-2005/jw-0131-soa.html
For more articles on Web services, browse the Java and Web Services section of JavaWorld's Topical Index: http://www.javaworld.com/channel_content/jw-webserv-index.shtml
For more articles on enterprise development, browse the Enterprise Java section of JavaWorld's Topical Index:
http://www.javaworld.com/channel_content/jw-enterprise-index.shtml

posted @ 2005-12-28 11:17 Flyingis 阅读(1624) | 评论 (0)编辑 收藏

Java容器分析--Map

    作者:Flyingis

标准的
Java类库中包含了几种类型的Map,它们都拥有同样的基本接口Map,但是行为特性各不相同,主要表现在效率、键值对的保存、元素呈现次序、对象的保存周期和判定键是否等价的策略等方面。

1.Map的功能方法

Map(interface): 维护labelvalue的关联性,使得可以通过label查找value

HashMap: Map基于散列表的实现,取代了Hashtable。插入和查询label/value的开销是固定的,并且可以通过构造器设置容量和负载因子,以调整容器的性能。

LinkedHashMap: HashMap的基础上做了一些改进,在迭代遍历它时,取得label/value的顺序是其插入的次序,或者是最近最少使用(LRU)的次序,速度上比HashMap要慢一点,但在迭代访问时速度会更快,主要原因是它使用了链表维护内部次序。

TreeMap: 查看labellabel/value时,元素会被排序,其次序由ComparableComparator决定,因此查询所得到的结果是经过排序的。另外,它是唯一带有subMap()方法的Map具体类,即返回一个子树。它也是SortedMap接口的唯一实现,subMap()方法也是从该接口继承的。

WeakHashMap: Weak Key映射,允许释放映射所指向的对象。当映射之外没有引用指向某个label时,此label可以被垃圾收集器回收。

IdentityHashMap: 使用==代替equals()label进行比较的散列映射。

2.hashCode()

         当使用标准库中的类Integer作为HashMaplabel时,程序能够正常运行,但是使用自己创建的类作为HashMaplabel时,通常犯一个错误。

         HashMap中通过label查找value时,实际上是计算label对象地址的散列码来确定value的。一般情况下,我们是使用基类Object的方法hashCode()来生成散列码,它默认是使用对象的地址来计算的,因此由第一个对象new Apple(5)和第二个对象new Apple(5)生成的散列码是不同的,不能完成正确的查找。通常,我们可以编写自己的hashCode()方法来覆盖基类的原始方法,但与此同时,我们必须同时实现equals()方法来判断当前的label是否与表中存在的label相同。正确的equals()方法满足五个条件:

(1)     自反性。对于任意的xx.equals(x)一定返回true

(2)     对称性。对于任意的xy,如果y.equals(x)返回true,则x.equals(y)也返回true

(3)     传递性。对于任意的xyz,如果有x.equals(y)返回truey.equals(z)返回true,则x.equals(z)一定返回true

(4)     一致性。对于任意的xy,如果对象中用于等价比较的信息没有改变,那么无论调用x.equals(y)多少次,返回的结果应该保持一致,要么一直是true,要么一直是false

(5)     对任何不是nullxx.equals(null)一定返回false

equals()比较的是对象的地址,如果要使用自己的类作为HashMaplabel,必须同时重载hashCode()equals()方法。

使用散列的目的:想要使用一个对象来查找另一个对象。使用TreeSetTreeMap也能实现此目的。另外,还可以自己实现一个Map,此时,必须提供Map.entrySet()方法来生成Map.Entry对象的Set

使用散列的价值:速度,散列使得查询可以快速进行。散列将label保存载数组中方便快速查询,因为存储一组元素最快的数据结构是数组,用它来表示label的信息(后面有信息的描述),而不是label本身。通过label对象计算得到一个数字,作为数组的下标,这个数字就是散列码(即前面所述的信息)。该散列码具体是通过定义在基类Object中,可能由程序员自定义的类覆盖的hashCode()方法,即散列函数生成。为了解决数组容量带来的限制,可以使不同的label生成相同的下标,保存在一个链表list中,每一个链表就是数组的一个元素。查询label时就可以通过对list中的信息进行查找,当散列函数比较好,数组的每个位置中的list长度较短,则可以快速查找到数组元素list中的某个位置,提高了整体速度。

散列表中的slot通常称为bucket,为了使散列分步均匀,bucket的值一般取质数。但事实证明,质数实际上并不是散列bucket的理想容量,近来Java散列实现都使用2的幂,具体如何验证以后再续。

3.HashMap的性能因子

容量(capacity): 散列表中bucket的数量。

初始化容量(initial capacity): 创建散列表时bucket的数量。可以在构造方法中指定HashMapHashSet的初始化容量。

尺寸(size): 散列表中记录的数量。(数组的元素个数,非list中元素总和)

负载因子(load factor): 尺寸/容量。负载因子为0,表示空的散列表,0.5表示半满的散列表。轻负载的散列表具有冲突少,适宜插入与查询的特点,但是使用迭代器遍历会比较慢。较高的负载会减少所需空间大小。当负载达到指定值时,容器会自动成倍地增加容量,并将原有的对象重新分配,存入新的bucket中,这个过程称为“重散列”。

4.重写hashCode()的关键

(1)     对同一个对象调用hashCode()都应该生成同样的值。

(2)     hashCode()方法不要依赖于对象中易变的数据,当数据发生变化时,hashCode()就会生成一个不同的散列码,即产生了一个不同的label

(3)     hashCode()不应依赖于具有唯一性的对象信息,例如对象地址。

(4)     散列码应该更关心速度,而不是唯一性,因为散列码不必是唯一的。

(5)     好的hashCode()应该产生分步均匀的散列码。在Effective Java(Addison-Wesley 2001)中,Joshua BlochhashCode()给出了设计指导,可以参考。

编写正确高效的hashCode()equals()可以参考ApacheJakarta Commons项目中的工具。

其它相关内容:
Java容器分析--数组
Java容器分析--List和Set

posted @ 2005-12-27 10:07 Flyingis 阅读(4333) | 评论 (3)编辑 收藏

GIS数据建库基本思想(下)

GIS数据建库基本思想(上)

3.      数据规范

这里说的数据规范,指的是可以被系统所正确识别的数据。这依赖于上述数据库建库的第一个过程,即数据库标准的制定和数据规范。这里的主要矛盾在于,因为 GIS  平台的不一致,各个平台对空间数据描述的模型不同,而导致了在一个平台上生成的数据在另一个平台不能正确读出,从而导致转换前后矢量或属性数据的丢失,甚至无法转换的结果。

例如, AutoCAD 存在拟合曲线 Spline 对象,图形块 Block 对象,区域 Region  对象,代理对象等许多特殊的图形对象,在 GIS 系统中没有相应的图形对象与之相对应。因此要想将这些数据入库,必须先将以上对象转化,使之变成 GIS 可以识别的图形对象。   AutoCAD  的扩展数据由于为 AutoCAD  所特有,因此也必须寻找解决办法 ( 例如数据格式转换 ) ,使之能被 GIS 所正确读取。

此外还包括数据规范中规定的各个图层之间相互的空间拓扑关系及属性数据等,这些都要求有相应的检测和修正工具予以保证。

4.      数据生产

数据生产过程主要包括准备阶段和数据输入阶段。以下为 AutoCAD 平台下数据的生产过程为例。

准备阶段

此过程包括定义图层名称,配置图层的各种属性(颜色,线性,线宽,图形符号等)。这一过程是数据生产的准备阶段,工作逻辑上非常简单,在认真设置和检查后,产生错误的可能性会很小。

数据生产阶段

包括栅格数据自动矢量化和人工输入两个比较大的方面,有时候全为人工输入。

栅格数据自动矢量化是通过扫描仪器输入栅格数据,然后通过图像识别算法,进行矢量跟踪,从而确定实体的空间位置。在目前的技术发展中,程序的算法往往不能完全识别出所需要的对象并进行正确的矢量化,若栅格数据是经过底图扫描而非遥感影像,可能还会出现扫面不清晰,因此会产成各种各样的问题。常见的错误主要有以下几种:

(1)     房屋等面状闭合物体留有缺口,即不封闭。

(2)     扫描后的线段存在很多重复点的现象。

(3)     扫描后的线段存在自相交的情况。

(4)     在图像边缘上的线段,扫描后出现畸变现象。

(5)     在图像的边缘存在数据丢失的现象。

(6)     由于图像定位不准,导致扫描后图像部分基准点偏移,从而导致相邻的地区存在图形重叠或交叉的现象。

其中基准点偏差的影响尤为显著,严重影响数据建库。一般情况下,我们需要封闭检查,重复点检查,自相交检查,基准点检查和校正等检查工具去发现和排除这些错误。在这些错误中,错误 1 2 3 在逻辑上比较简单,相对比较好解决。错误 4 则比较难于检查和解决。

人工输入是指数据录入人员按照要求用鼠标或绘图议等手工在图纸上进行绘图,并设置和添加各种属性的过程。这一过程十分繁重的,并且工作具有重复性和枯燥性等特点,因此容易造成各种错误,从而影响数据质量。产成的错误的原因主要有两个:

精度问题造成的错误,这种原因往往造成图形拓扑关系错误。例如,应该闭合的面状物体没有闭合,应该端点相连的直线没有连接,不应该重叠的线段存在重叠的部分,不应该交叉的图形存在交叉,面与面之间存在缝隙,面与面之间发生重叠,基准点和控制点定位不准确等等。

人为疏忽造成的原因。例如,有属性的图形物体忘记给属性赋值,导致属性丢失;有属性的图形物体错误赋值,导致属性错误;图幅边框被删除或者移动位置;图幅边界上的图形没有很好的完成接边处理,造成相邻图形不匹配等等。这些错误都经常的会在数据生产过程中发生,如果不加以检测和修正,将直接影响建库的正确性和准确性,应予以注意。

5.      小结

         从以上分析可以看出,数据建模、数据规范、数据生产都是 GIS 数据顺利、准确入库的关键,在整个过程中,数据校验起到了非常重要的作用,在实际操作中,需要系统理论知识和经验知识来作为建立 GIS 数据库的架构支撑。根据个人有限的系统工程方面的理论知识,只能对数据校验做出如下概述:

(1)     首先,需要对准备入库的各种源数据进行研究和分析,从中发现数据中存在的明显的错误,并估计潜在的错误。

(2)     根据数据建库标准和数据规范,分析这些错误可能对建库造成的影响,按照严重程度、优先级别、逻辑关系等将错误分类,并制定处解决问题的方案。

(3)     按照制定的解决方案有计划、有步骤的纠正这些错误,使之符合建库的规范。

(4)     这样循环检查几次,尽量消除数据中的错误,一般情况下,总会有少量错误存在。

(5)     当已经很难找出错误时,可以开始进行抽样检测,并小规模进行试验性入库。

(6)     在试验性入库成功后,进行大批量的实际入库。

(7)     入库完毕,对入库成果进行抽样检查,查找不正确的地方,并进行修正。

(8)     GIS 数据入库正式完成,交付使用。

经过上述过程,整个建库工作就已经完成。上文所述,只是个人在 GIS 数据建库方面的一点个人经验和系统知识,在今后的实际工作中仍需不断完善、深入。

原文链接:http://www.gissky.net/blog/blog.asp?name=bluewood

posted @ 2005-12-25 15:24 Flyingis 阅读(2796) | 评论 (5)编辑 收藏

GIS数据建库基本思想(上)

地理信息系统的建设中,数据库的建设极为重要,基础地形库的建设大概要占到整个系统的 60% 甚至更高。因此,若在建库的过程中碰到问题,将导致建库的困难,甚至无法完成建库的工作。要解决建库遇到的各种问题并顺利完成建库,就要对建库的整个过程进行分析,从中找出影响建库的最主要的因素,并认真的分析这些因素产生的根本原因,制定出解决这些问题的解决方案,完成重要的建库工作。  

数据库建库主要有三个过程:

First -- 数据库建模。主要是根据具体行业的特点及对其的理解,制定出数据规范,在逻辑上建设数据库。

Second -- 数据校验。主要是检测数据的正确性,保证数据质量。

Third -- 数据入库。主要是将获取的各种数据,例如纸制数据,矢量数据,栅格数据,遥感影像数据等准确的导入到数据库中。

         下面对数据库建库的整个过程进行详细分析。

1.      数据建模

数据建模的目的是根据对应用行业的理解,在逻辑和概念上对数据库进行设计,其影响的是数据库建设完毕后的合理性、通用性和可扩展性。建模是否成功将直接影响到系统是否易用、易扩展,甚至是否成功。地理信息数据库建库过程中遇到的各种问题主要是数据问题,对系统成功进行了建模之后,若数据存在问题,将直接影响到数据的入库。

2.      数据入库

在数据入库的过程中,其核心是如何依据所制定的数据规范将各种格式的数据,准确的、快速的导入到数据库中。在这个过程中遇到的问题,其根本就是如何解决不同平台之间数据集成的问题。在《 GIS 开发者》第八期电子杂志中,曾提出共相式地理信息系统,其目的之一也是为了解决数据源的集成问题。在目前,实现地理信息多源数据集成的方式大致有三种,即数据互操作模式,直接数据访问模式和数据格式转换模式。  

共相式GIS支持多种数据格式的技术框架示意图.gif

共相式
GIS 支持多种数据格式的技术框架示意图

( 注:该图引用自《 GIS 开发者》第八期电子杂志 )

(1)     数据互操作模式。数据互操作模式是 OpenGIS Consortium OGC )制定的规范。这种模式和数据入库的思路有所不同。

(2)     直接数据访问模式。直接数据访问模式是指在一个 GIS 软件中,实现对其他软件数据格式的直接访问,用户可以使用单个 GIS  软件存取多种数据格式。以 ArcGIS 为例,它可以打开多种 GIS  平台及其它相关软件的数据。

(3)     数据格式转换模式格式转换模式是传统的 GIS 数据集成方法,也是入库的基本思想。在这种模式下,其他数据格式经专门的数据转换程序进行格式转换后,就可以进行入库了。例如,在 ArcToolBox( 版本 9 以后被整合到 ArcMap ArcCatalog ) 里,就有多种数据格式转换的工具。

数据格式转换是目前 GIS 系统集成的主要办法。现在基本上每个主流 GIS 平台都提供了一些数据转换工具,以 ESRI 公司的 ArcGIS  平台提供了 ArcToolBox 工具箱,功能相对完善,基本上支持所有市面上各种主流的 GIS 数据,例如 Autodesk 公司的 DWG 格式文件和 DXF 格式文件, MapInfo  公司的 MIF  格式, Intergraph DGN 格式,以及各种栅格图形数据等等,基本上满足了一般数据入库的要求。此外,还有其它许多专门的数据格式转换工具可以使用。由此可以看出,只要提供的源数据是正确的,符合规范的,那么利用上述工具就可以将数据导入到数据库中,从而顺利的完成建库的工作。因此,源数据的准确性和规范性就成为建库成功的十分关键的因素。由此看来,数据校验就成为建库能否顺利进行的关键所在。

数据校验需要完成哪些工作,怎样进行校验与把关才能在建库之初就能预测各种潜在的问题,因此,需要仔细分析导致数据不准确、不规范的原因。一般情况下,需要从数据规范和数据生产过程中考虑。

GIS数据建库基本思想(下)


原文链接:http://www.gissky.net/blog/blog.asp?name=bluewood

文章进行了简单增改,对于本文的争议请看文后的评论。

posted @ 2005-12-22 18:43 Flyingis 阅读(3566) | 评论 (5)编辑 收藏

Java容器分析--List和Set

    作者:Flyingis

    容器类可以大大提高编程效率和编程能力,在
Java2中,所有的容器都由SUN公司的Joshua Bloch进行了重新设计,丰富了容器类库的功能。

         Java2容器类类库的用途是“保存对象”,它分为两类:

Collection----一组独立的元素,通常这些元素都服从某种规则。List必须保持元素特定的顺序,而Set不能有重复元素。

Map----一组成对的“键值对”对象,即其元素是成对的对象,最典型的应用就是数据字典,并且还有其它广泛的应用。另外,Map可以返回其所有键组成的Set和其所有值组成的Collection,或其键值对组成的Set,并且还可以像数组一样扩展多维Map,只要让Map中键值对的每个“值”是一个Map即可。

1.
迭代器

       迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。

       Java中的Iterator功能比较简单,并且只能单向移动:

(1)    使用方法iterator()要求容器返回一个Iterator。第一次调用Iteratornext()方法时,它返回序列的第一个元素。

(2)    使用next()获得序列中的下一个元素。

(3)    使用hasNext()检查序列中是否还有元素。

(4)    使用remove()将迭代器新返回的元素删除。

IteratorJava迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。

2.List的功能方法

List(interface): 次序是List最重要的特点;它确保维护元素特定的顺序。ListCollection添加了许多方法,使得能够向List中间插入与移除元素(只推荐LinkedList使用)。一个List可以生成ListIterator,使用它可以从两个方向遍历List,也可以从List中间插入和删除元素。

ArrayList: 由数组实现的List。它允许对元素进行快速随机访问,但是向List中间插入与移除元素的速度很慢。ListIterator只应该用来由后向前遍历ArrayList,而不是用来插入和删除元素,因为这比LinkedList开销要大很多。

LinkedList: 对顺序访问进行了优化,向List中间插入与删除得开销不大,随机访问则相对较慢(可用ArrayList代替)。它具有方法addFirst()addLast()getFirst()getLast()removeFirst()removeLast(),这些方法(没有在任何接口或基类中定义过)使得LinkedList可以当作堆栈、队列和双向队列使用。

3.Set的功能方法

Set(interface): 存入Set的每个元素必须是唯一的,因为Set不保存重复元素。加入SetObject必须定义equals()方法以确保对象的唯一性。SetCollection有完全一样的接口。Set接口不保证维护元素的次序。

HashSet: 为快速查找而设计的Set。存入HashSet的对象必须定义hashCode()

TreeSet: 保持次序的Set,底层为树结构。使用它可以从Set中提取有序的序列。

LinkedHashSet: 具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入的次序)。于是在使用迭代器遍历Set时,结果会按元素插入的次序显示。

       HashSet采用散列函数对元素进行排序,这是专门为快速查询而设计的;TreeSet采用红黑树的数据结构进行排序元素;LinkedHashSet内部使用散列以加快查询速度,同时使用链表维护元素的次序,使得看起来元素是以插入的顺序保存的。需要注意的是,生成自己的类时,Set需要维护元素的存储顺序,因此要实现Comparable接口并定义compareTo()方法。

其它相关内容:
Java容器分析--数组
Java容器分析--Map

posted @ 2005-12-21 15:06 Flyingis 阅读(2587) | 评论 (0)编辑 收藏

热点讨论--"Java? It's So Nineties"

作者:Flyingis

贴一则消息。
今天在各大网站上都看到这条醒目的新闻:"Java? It's So Nineties"。好像全世界的Java程序员和其他程序员都在讨论这个话题,虽然有时觉得这种话题有点无聊之闲,但关注程度如此之高,赋予了我们关注的意义。也许,从中我们能了解Java今后的大致发展方向。
--------------------------------------
CSDN--缺乏发展空间 Java不及LAMP和.NET? 
BusinessWeek 昨天的一篇文章
"Java? It's So Nineties" 引起了广泛的讨论。其中的主要观点认为,Java在各领域均缺乏发展空间,注定比不上LAMP 和.NET。

文中提到,Sun从前的一位管理人员开了一家 "focused on MySQL and PHP" 公司,宣称“Java是恐龙”;PHP公司主席Marc Andreesen声称,“我们可以看到一种由Java 向PHP转移的现状”;Microsoft's .NET director-John Montgomery说道,“没有人能用Java赚到钱。”

该文作者Steve Hamm 通过列举了大量的统计信息,其中对象主要包括LAMP、.NET、AJAX,等等,试图向读者传达这样一个信号:Java已经走入穷途末路,请广大开发者们赶快迷途知返,悬崖勒马才好。作者甚至以AJAX图书销售量大于Java图书为例。

虽然作者的文章中一些数据和言论的真实性值得商榷,但有一点却是值得我们思考:Java未来的发展方向在哪里?

原文链接:
http://www.businessweek.com/technology/content/dec2005/tc20051213_042973.htm

相关评论:
Is Java losing to LAMP and .NET?
http://www.theserverside.com/news/thread.tss?thread_id=38081
Java? It's So Nineties
http://www.javalobby.org/java/forums/t59582.html

MATRIX--Java被Lamp和.Net赶超?无稽之谈……
BusinessWeek Online 昨天有一篇文章,叫做:"Java? It's So Nineties"。内容是,java虽然异常强大,但是逐渐被Lamp和.Net赶超。
理由是:PHP和AJAX正在变得很受欢迎,特别是AJAX,图书销量正在逐渐赶超Java的图书销量。
另外一个理由是:对于在linux上搭建轻量级的简单的应用的时候,也不需要用到Java。
文章在Tss引起广泛讨论。

实际上,多数开发者都认为,这个结论纯属无稽之谈。并且毫无意义。随便列举几个理由:
1.  企业级开发,Java毫无疑问是完全占据优势的。
2.  Dyanimics 和Groovy 是Java 可以较大提升的一个地方,这使得Java更加动态,更适应小型应用。而EJB这些,就更不用说了,LAMP和.Net,基本上是不适用了。
3.  PHP很受欢迎,只是证明了PHP在很多简单应用上,开发者上手比较快而已。
4.  最关键的是,PHP和JAVA也不是一个层面比较的东西,如果要比较,那么就是MODE-1的JSP和PHP比较。特别是O/R, AOP, MVC, Patterns, XML config files, Tag libraries 等,在PHP中要实现还是要很长一段时间。
等等了……

毫无意义的比较,本来实在不想post这篇评论,然后在TSS上引起广泛评论,想让大家也给一些意见。总之,大家一致觉得,BusinessWeek 的结论是无稽之谈。

对于BusinessWeek的观点,你的看法又如何?
--------------------------------------------


另外在Matrix上有两则最新的消息,不知道AJAX要火到什么程度,IT这个行业真是说不准:
------------------------------------
MyEclipse 4.1 M2 发布
    MyEclipse 4.1 M2 发布了。有很多项值得关注的特性:支持AJAX和Web 2.0,提升了Javascript 编辑器,增加了Javascript 调试器等等..
基于Ajax的Web框架Echo2 2.0发布
    NextApp 宣布Echo2  2.0发布了。Echo2是一个基于Mozilla Public License的开源WEB框架。一个可以用于开发基于Web胖客户端应用程序的框架。
-----------------------------------

posted @ 2005-12-18 19:32 Flyingis 阅读(1033) | 评论 (5)编辑 收藏

ClassCastException深入分析

作者:Flyingis

      ClassCastException
JVM在检测到两个类型间转换不兼容时引发的运行时异常。此类错误通常会终止用户请求。在执行任何子系统的应用程序代码时都有可能发生ClassCastException异常。通过转换,可以指示Java编译器将给定类型的变量作为另一种变量来处理。对基础类型和用户定义类型都可以转换。Java语言规范定义了允许的转换,其中大多数可在编译时进行验证。不过,某些转换还需要运行时验证。如果在此运行时验证过程中检测到不兼容,JVM就会引发ClassCastException异常。例如:

Fruit f;

Apple a = (Apple)f;

当出现下列情况时,就会引发ClassCastException异常:

1.        FruitApple类不兼容。当应用程序代码尝试将某一对象转换为某一子类时,如果该对象并非该子类的实例,JVM就会抛出ClassCastException异常。

2.        FruitApple类兼容,但加载时使用了不同的ClassLoader。这是这种异常发生最常见的原因。在这里,需要了解一下什么是ClassLoader


ClassLoader

         ClassLoader是允许JVM查找和加载类的一种Java类。JVM有内置的ClassLoader。不过,应用程序可以定义自定义的ClassLoader。应用程序定义新的ClassLoader通常出于以下两种原因:

1.        自定义和扩展JVM加载类的方式。例如,增加对新的类库(网络、加密文件等)的支持。

2.        划分JVM名称空间,避免名称冲突。例如,可以利用划分技术同时运行同一应用程序的多个版本(基于空间的划分)。此项技术在应用服务器(WebLogic Server)内的另一个重要用途是启用应用程序热重新部署,即在不重新启动JVM的情况下启动应用程序的新版本(基于时间的划分)

ClassLoader按层级方式进行组织。除系统BootClassLoader外,其它ClassLoader都必须有父ClassLoader

在理解类加载的时候,需要注意以下几点:

1.        永远无法在同一ClassLoader中重新加载类。“热重新部署”需要使用新的ClassLoader。每个类对其ClassLoader的引用都是不可变的:this.getClass().getClassLoader()

2.        在加载类之前,ClassLoader始终会先询问其父ClassLoader(委托模型)。这意味着将永远无法重写“核心”类。

3.        同级ClassLoader间互不了解。

4.        由不同ClassLoader加载的同一类文件也会被视为不同的类,即便每个字节都完全相同。这是ClassCastException的一个典型原因。

5.        可以使用Thread.setContextClassLoader(a)ClassLoader连接到线程的上下文。

基于以上的基本原理,可以加深大家对ClassCastException的理解,和在碰到问题时提供一种解决问题的思路。

 

参考文献:

dev2dev专刊 2005 第二期

j2sdk-1_5_0-doc

posted @ 2005-12-18 18:57 Flyingis 阅读(28687) | 评论 (4)编辑 收藏

Java容器分析--数组

         作者:Flyingis

    数组是
Java语言内置的类型,除此之外,Java有多种保存对象引用的方式。Java类库提供了一套相当完整的容器类,使用这些类的方法可以保存和操纵对象。下面分别进行讨论,在研究Java容器类之前,先了解一下Java数组的基本功能和特性。

1.  数组的基本特性

         数组与其它种类的容器(List/Set/Map)之间的区别在于效率、确定的类型和保存基本类型数据的能力。数组是一种高效的存储和随机访问对象引用序列的方式,使用数组可以快速的访问数组中的元素。但是当创建一个数组对象(注意和对象数组的区别)后,数组的大小也就固定了,当数组空间不足的时候就再创建一个新的数组,把旧的数组中所有的引用复制到新的数组中。

         Java中的数组和容器都需要进行边界检查,如果越界就会得到一个RuntimeException异常。这点和C++中有所不同,C++vector的操作符[]不会做边界检查,这在速度上会有一定的提高,Java的数组和容器会因为时刻存在的边界检查带来一些性能上的开销。

         Java中通用的容器类不会以具体的类型来处理对象,容器中的对象都是以Object类型处理的,这是Java中所有类的基类。另外,数组可以保存基本类型,而容器不能,它只能保存任意的Java对象。

         一般情况下,考虑到效率与类型检查,应该尽可能考虑使用数组。如果要解决一般化的问题,数组可能会受到一些限制,这时可以使用Java提供的容器类。 

2.  操作数组的实用功能

         java.util.Arrays类中,有许多static静态方法,提供了操作数组的一些基本功能:

         equals()方法----用于比较两个数组是否相等,相等的条件是两个数组的元素个数必须相等,并且对应位置的元素也相等。

         fill()方法----用以某个值填充整个数组,这个方法有点笨。

         asList()方法----接受任意的数组为参数,将其转变为List容器。

         binarySearch()方法----用于在已经排序的数组中查找元素,需要注意的是必须是已经排序过的数组。当Arrays.binarySearch()找到了查找目标时,该方法将返回一个等于或大于0的值,否则将返回一个负值,表示在该数组目前的排序状态下此目标元素所应该插入的位置。负值的计算公式是“-x-1”x指的是第一个大于查找对象的元素在数组中的位置,如果数组中所有的元素都小于要查找的对象,则x = a.size()。如果数组中包含重复的元素,则无法保证找到的是哪一个元素,如果需要对没有重复元素的数组排序,可以使用TreeSet或者LinkedHashSet。另外,如果使用Comparator排序了某个对象数组,在使用该方法时必须提供同样的Comparator类型的参数。需要注意的是,基本类型数组无法使用Comparator进行排序。

         sort()方法----对数组进行升序排序。

         Java标准类库中,另有static方法System.arraycopy()用来复制数组,它针对所有类型做了重载。

3.  数组的排序

         Java1.01.1两个版本中,类库缺少基本的算法操作,包括排序的操作,Java2对此进行了改善。在进行排序的操作时,需要根据对象的实际类型执行比较操作,如果为每种不同的类型各自编写一个不同的排序方法,将会使得代码很难被复用。一般的程序设计目标应是“将保持不变的事物与会发改变的事物相分离”。在这里,不变的是通用的排序算法,变化的是各种对象相互比较的方式。

Java有两种方式来实现比较的功能,一种是实现java.lang.Comparable接口,该接口只有一个compareTo()方法,并以一个Object类为参数,如果当前对象小于参数则返回负值,如果相等返回零,如果当前对象大于参数则返回正值。另一种比较方法是采用策略(strategy)设计模式,将会发生变化的代码封装在它自己的类(策略对象)中,再将策略对象交给保持不变的代码中,后者使用此策略实现它的算法。因此,可以为不同的比较方式生成不同的对象,将它们用在同样的排序程序中。在此情况下,通过定义一个实现了Comparator接口的类而创建了一个策略,这个策略类有compare()equals()两个方法,一般情况下实现compare()方法即可。

使用上述两种方法即可对任意基本类型的数组进行排序,也可以对任意的对象数组进行排序。再提示一遍,基本类型数组无法使用Comparator进行排序。

Java标准类库中的排序算法针对排序的类型进行了优化——针对基本类型设计了“快速排序”,针对对象设计的“稳定归并排序”。一般不用担心其性能。

其它相关内容:
Java容器分析--List和Set
Java容器分析--Map

posted @ 2005-12-15 20:56 Flyingis 阅读(2880) | 评论 (3)编辑 收藏

南京大屠杀官方网站

    已经懒得再去数落小日本的罪行了,去年12月侵华日军南京大屠杀遇难同胞纪念馆开通了南京大屠杀史实中文网站,今年又开通了英文网站,让全世界都记住这段历史。

    中文网站:
http://www.nj1937.org
    英文网站: http://english.nj1937.org

posted @ 2005-12-15 16:07 Flyingis 阅读(743) | 评论 (1)编辑 收藏

浅议类型识别与反射机制

    作者:Flyingis

    运行时类型识别
(Run-time Type Identification, RTTI)主要有两种方式,一种是我们在编译时和运行时已经知道了所有的类型,另外一种是功能强大的“反射”机制。

       要理解RTTIJava中的工作原理,首先必须知道类型信息在运行时是如何表示的,这项工作是由“Class对象”完成的,它包含了与类有关的信息。类是程序的重要组成部分,每个类都有一个Class对象,每当编写并编译了一个新类就会产生一个Class对象,它被保存在一个同名的.class文件中。在运行时,当我们想生成这个类的对象时,运行这个程序的Java虚拟机(JVM)会确认这个类的Class对象是否已经加载,如果尚未加载,JVM就会根据类名查找.class文件,并将其载入,一旦这个类的Class对象被载入内存,它就被用来创建这个类的所有对象。一般的RTTI形式包括三种:

1.       传统的类型转换。如“(Apple)Fruit”,由RTTI确保类型转换的正确性,如果执行了一个错误的类型转换,就会抛出一个ClassCastException异常。

2.       通过Class对象来获取对象的类型。如

Class c = Class.forName(“Apple”);

Object o = c.newInstance();

3.       通过关键字instanceofClass.isInstance()方法来确定对象是否属于某个特定类型的实例,准确的说,应该是instanceof / Class.isInstance()可以用来确定对象是否属于某个特定类及其所有基类的实例,这和equals() / ==不一样,它们用来比较两个对象是否属于同一个类的实例,没有考虑继承关系。

 

反射

       如果不知道某个对象的类型,可以通过RTTI来获取,但前提是这个类型在编译时必须已知,这样才能使用RTTI来识别。即在编译时,编译器必须知道所有通过RTTI来处理的类。

使用反射机制可以不受这个限制,它主要应用于两种情况,第一个是“基于构件的编程”,在这种编程方式中,将使用某种基于快速应用开发(RAD)的应用构建工具来构建项目。这是现在最常见的可视化编程方法,通过代表不同组件的图标拖动到图板上来创建程序,然后设置构件的属性值来配置它们。这种配置要求构件都是可实例化的,并且要暴露其部分信息,使得程序员可以读取和设置构件的值。当处理GUI时间的构件时还必须暴露相关方法的细细,以便RAD环境帮助程序员覆盖这些处理事件的方法。在这里,就要用到反射的机制来检查可用的方法并返回方法名。Java通过JavaBeans提供了基于构件的编程架构。

       第二种情况,在运行时获取类的信息的另外一个动机,就是希望能够提供在跨网络的远程平台上创建和运行对象的能力。这被成为远程调用(RMI),它允许一个Java程序将对象分步在多台机器上,这种分步能力将帮助开发人员执行一些需要进行大量计算的任务,充分利用计算机资源,提高运行速度。

       Class支持反射,java.lang.reflect中包含了Field/Method/Constructor类,每个类都实现了Member接口。这些类型的对象都是由JVM在运行时创建的,用来表示未知类里对应的成员。如可以用Constructor类创建新的对象,用get()set()方法读取和修改与Field对象关联的字段,用invoke()方法调用与Method对象关联的方法。同时,还可以调用getFields()getMethods()getConstructors()等方法来返回表示字段、方法以及构造器的对象数组。这样,未知的对象的类信息在运行时就能被完全确定下来,而在编译时不需要知道任何信息。

       另外,RTTI有时能解决效率问题。当程序中使用多态给程序的运行带来负担的时候,可以使用RTTI编写一段代码来提高效率。

Happy Birthday to myself!

posted @ 2005-12-11 14:43 Flyingis 阅读(2252) | 评论 (9)编辑 收藏

Google新服务--出行路线规划服务

    作者: Flyingis

    Google现在的火热程度都快超过当年Windows 95,在推出Google Talk / Google Map / Google Earth / Gmail / Picasa2 等等重量级服务及软件以后,近日又推出了一项名为Transit Trip Planner(出行路线规划)的新服务,目的是为出行用户找出最便捷的公交路线。

    公交线路服务是地理信息的重要应用之一或者是将来全面应用的热点之一,在当今地理信息发展到十字路口,在技术理论理念的突破步履维艰的时候,Google公司的Google Map / Google Earth 和即将在全球普及的Transit Trip Planner服务给地理信息世界注入了一剂强心针,在理想地理信息应用和现阶段的实际应用之间找到了一个平衡点,和Google公司一贯作风一样,以简洁实用高效的特点吸引了无数人的眼光,提供了最简便的应用。

2005120901.jpg

2005120902.jpg



    Transit Trip Planner服务需要用户输入他们的首选路线,例如出发地、目的地、出行日期和时间等,然后它会收集所有的公交调度信息,为用户制订出行路线计划。这项服务目前还处于测试阶段,并且还没有和Google本地搜索整合,相信不久就可以和Google Map / Google Earth 一样在全球得到应用,进一步改善用户的地图服务体验,以现有的基础提供最实用的地图影像服务。Google和Sun公司已经建立了良好的合作关系,Google的发展势头将对Java应用的进一步推广产生积极的作用,让我们一起期待Google和Java的发展……

posted @ 2005-12-09 20:04 Flyingis 阅读(1501) | 评论 (0)编辑 收藏

Google的Offer

   作者:Flyingis

   昨天在Matrix上看到一贴子http://www.matrix.org.cn/thread.shtml?topicId=33198&forumId=11,具体的内容我贴过来了:

-------------------------------------------------
   
朋友刚硕士毕业拿到了GoogleOffer!这里gx一下,顺便透露一下Google的情况:

   
背景:一流大学CS硕士毕业 跨国软件公司实习半年
   
应征职位:Software Engineer
   
面试笔试一堆(包括从美国打来的越洋长途提问),最后是面见李开复,加工作餐一顿(他说大约是收50个关门弟子,但个人认为李替google炒作的味道太重)
   
月薪:16k左右
   
其它福利:Google的股票40(现在市值超过400$ 每股)

   
总的来说,待遇还不是很有竞争力。
   
不过在国内也是过得去了。
------------------------------------------------

   
不看作者的评论,我觉得在国内有这种待遇已经很不错了,当然对于一家著名的外资企业,开出这样的工资也很正常,但对于国内大多数软件开发人员来讲,能拿到这份工作却是可望不可及。

   
这段时间在举行Google中国编程大赛,我第一次听说是在印度举行的,Google通过这种活动不仅可以扩大自己公司在世界上的影响,还可以招募到最优秀的开发人员,并提供优厚的条件。和当今中国大多数公司相反,以Google为代表的公司真正做到了人性化的管理,虽说公司也是为了赚钱,但至少它把员工当成了自己的人,刚成为正式员工就持有公司的股票。好像有点么发牢骚的味道,其实并不想也没必要,因为在各种不同的环境站在不同的角度,都能为现在国内的软件行业的环境、行情说出许多不同的正当理由,也没有争论甚至埋怨中国大多数软件企业和政府职能的必要。如果感兴趣可以看看这篇文章——中国企业对软件人才利用的思考

   
这里想说的是,IT人的学习方法与思维方式。像许多年轻人一样,我也曾经对各种开发工具、开发语言产生过浓厚的兴趣,并且现在仍然在持续。在学校有位工作过8年的博士曾对我说,在软件这个行业很刺激,很有挑战力,并且充满活力,最初我们总是有冲劲去学习各种技术,攻克开发语言中的各种难关,使用最流行的框架去实现自己的想法,但是当我们工作一段时间后,会发现自己的青春全花费在了这些框架、语言和工具上面。对于部分人,他们会成为开发高手,他们对于各种开发工具了如指掌,并且看着这些产品更新换代,积累了丰富的经验,加上这几年对项目的理解,他们可以成为项目经理甚至更高。但是对于大多数人,却没有这么幸运,因为公司不需要这么多的项目经理,不需要这么多的架构师,那他们怎么办,这就引出了从前几年开始大家就一直讨论的程序员过了三十怎么办之类的热门话题。

   
电脑这玩意现在太热,产品的更新换代,技术的不断发展,成本的不断降低,已经将电脑带入的千家万户,从前几年大学校园对计算机科学与技术专业的扩招,到各种软件学院和培训机构的兴起,似乎已经给软件产业提供了充足的后备力量与人力资源。但不幸的是,现在大家在校园中所公认的电脑高手,已经逐渐变成Java语言高手、VC高手、VB高手等等,他们能用Struts+Hibernate+MySQL数据库构建一套教师课程评价系统,能用VB.net+SQLServer设计一套图书信息管理软件等。当然,在校园里能做出这些系统的人今后的确能在软件行中站稳脚跟,占据一席之地,但不是真正的高手,要做核心开发人员都需要付出更多的努力。然而更多的人,甚至达不到他们的水平,却不停的在图书馆看书,凭着自己最初极大的兴趣学习这些开发工具,在中途听过一次讲座,或是经过某些高手的指导后,又改学另外一门被公认最有发展潜力的语言。只要花了时间,等到毕业时,大家的确可以成为一名程序员,工资1000左右,2000不到,每天不停加班,程序写了又改,改了又写。中国需要这些程序员,但不需要这么多这样的程序员,程序员能力水平构成了一座金字塔,底层的人即初级程序员太多了!再看看书店中泛滥的开发相关的书籍,我不禁想说,我们该冷静了!

   
国外的知名IT企业,它们代表了IT的发展方向,它们需要什么样的软件人才?是精通算法的人员,是精通架构的人员。如果你只会用C语言,但是精通各种常见算法、数据结构,并且能够自己设计优秀的算法,但只是基本了解Java语法结构,Google很有可能会考虑你。如果你精通JavaVB,却对计算机体系结构、编译原理、数据结构知之甚少,我想Google很难被你的综合能力所打动。废话了一大堆,在这里才说出我想说的话,作为一个潜资历的懂一点开发的人来说,这样评价似乎欠火候,但我想写下一点自己所想,记录自己这一刻的思维,并欢迎大家讨论、指点,和大家一起共勉!

posted @ 2005-12-07 15:05 Flyingis 阅读(2849) | 评论 (4)编辑 收藏

Java虚拟机简介[转载]

     摘要: 一、什么是Java虚拟机   Java虚拟机是一个想象中的机器,在实际的计算机上通过软件模拟来实现。Java虚拟机有自己想象中的硬件,如处理器、堆栈、寄存器等,还具有相应的指令系统。   1.        为什么要使用Java虚拟机 Java语言的一个非常重要的特点就是与平台的无关性。而使用Jav...  阅读全文

posted @ 2005-12-05 16:26 Flyingis 阅读(488) | 评论 (0)编辑 收藏

关键字new和newInstance方法区别

    作者:Flyingis

    在初始化一个类,生成一个实例的时候,newInstance()方法和new关键字除了一个是方法,一个是关键字外,最主要有什么区别?它们的区别在于创建对象的方式不一样,前者是使用类加载机制,后者是创建一个新类。那么为什么会有两种创建对象方式?这主要考虑到软件的可伸缩、可扩展和可重用等软件设计思想。

    Java中工厂模式经常使用newInstance()方法来创建对象,因此从为什么要使用工厂模式上可以找到具体答案。 例如:
    class c = Class.forName(“Example”);
    factory = (ExampleInterface)c.newInstance();

    其中ExampleInterface是Example的接口,可以写成如下形式:
    String className = "Example";
    class c = Class.forName(className);
    factory = (ExampleInterface)c.newInstance();

    进一步可以写成如下形式:
    String className = readfromXMlConfig;//从xml 配置文件中获得字符串
    class c = Class.forName(className);
    factory = (ExampleInterface)c.newInstance();

    上面代码已经不存在Example的类名称,它的优点是,无论Example类怎么变化,上述代码不变,甚至可以更换Example的兄弟类Example2 , Example3 , Example4……,只要他们继承ExampleInterface就可以。

    从JVM的角度看,我们使用关键字new创建一个类的时候,这个类可以没有被加载。但是使用newInstance()方法的时候,就必须保证:1、这个类已经加载;2、这个类已经连接了。而完成上面两个步骤的正是Class的静态方法forName()所完成的,这个静态方法调用了启动类加载器,即加载java API的那个加载器。

    现在可以看出,newInstance()实际上是把new这个方式分解为两步,即首先调用Class加载方法加载某个类,然后实例化。 这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好的灵活性,提供给了一种降耦的手段。

    最后用最简单的描述来区分new关键字和newInstance()方法的区别:
    newInstance: 弱类型。低效率。只能调用无参构造。
    new: 强类型。相对高效。能调用任何public构造。

posted @ 2005-12-03 16:48 Flyingis 阅读(1291) | 评论 (3)编辑 收藏

Vector & ArrayList 哪一个更好?为什么?[转载]

有的时候 Vector更好一些;有的时候ArrayList 更好一些;有的时候你一个也不想用。但愿,你不是在期望一个简单明了的答案,因为答案因你在用他们做什么而定。下面是要考虑的四个方面:

API
同步-Synchronization
数据增长-Data growth
使用方法-Usage patterns

让我一个一个来解释吧。

API
在The Java Programming Language (Addison-Wesley, June 2000) 中Ken Arnold, James Gosling, 和 David Holmes 是这样描述Vector的,它是更ArrayList类似的一个东西,所以从API的观点来看,它们俩是很相似的。但是,它们之间还是有些微的差别的。

Synchronization
Vectors是可同步化的,意思就是说,任何操作Vector的内容的方法都是线程安全的,相反的,另一方面,ArrayList是不可同步化的,所以也不是线程安全的。如果你知道了这些的话,你就会发现,Vector的同步会让它在性能发方面有一些小问题。所以,如果你不需要线程安全的话,那么就使用ArrayList吧。为什么要为没有必要的同步付出代价呢?

Data growth
实际上,不管是ArrayList还是Vector,在它们内部都是使用一个Array来保存数据的。编程过程中,在使用它们任何一个的时候,你都需要记住这一点。你在往一个ArrayList或者Vector里插入一个元素的时候,如果内部数组空间不够了,这个对象(译者按:指的是你使用的ArrayList或者Vector)就要扩展它的大小。Vector在默认情况下是产生一个双倍大小,而ArrayList增加50%的大小。只要你合理的使用这些类,你就可以结束你在增加新的元素的时候所付出的性能代价。把对象(译者按:指的是你使用的ArrayList或者Vector)的初始化容量指定为你编程过程中所能用到的最大的容量总是最好的办法。仔细的指定容量,你可以避免以后改变内部Array容量,所要付出的代价。如果你并不知道到底有多少个数据,当是你知道数据的增长率,Vector确实有一点点优势,因为你可以指定增加值(译者按,如果没有猜错的话,作者说的方法应该是setSize(int newSize)  Sets the size of this vector.)。

Usage patterns
ArrayList和Vector在从指定位置取得元素,从容器的末尾增加和删除元素都非常的有效,所有的这些操作都能在一个常数级的时间(O(1))内完成。但是从一个其他的位置增加和删除一个元素就显得颇为费时,差不多需要的时间为O(n-i),这里的n代表元素个数,i代表要增加和删除的元素所在的位置。这些操作需花费更多的时间,因为你需要挨个移动i和更高位置的元素。那么,以上这些到底说明了什么呢?

这意味着,如果你取得一个元素,或者从数组末尾增加或删除一个元素的话,随便你使用Vector和ArrayList。如果你想要对数组内容做其他操作的话,那么就为自己好另一个容器吧。比喻说,LinkedList可以在常数级时间(O(1))内为任意一个位置的元素增加和删除。但是,取得一个元素,会稍微慢一点,时间要用O(i) ,这个i是元素的位置。通过ArrayList也是很简单的,因为你可以简单使用一个索引,而不是构造一个iterator 。LinkedList也为每个插入的元素建立一个内部对象。所以,你也必须知道,同时产生了垃圾对象。

最后,Practical Java (Addison-Wesley, Feb. 2000) Peter Haggar 里的“实践41“建议你使用一个普通的原始的数组来代替Vector和ArrayListe,特别是对效率优先的代码来说。通过使用数组(array),你可以避免同步,额外的方法调用,非理想化的大小改变。你付出的只是额外的开发时间。

原文链接:http://www.javaworld.com/javaworld/javaqa/2001-06/03-qa-0622-vector.html

posted @ 2005-11-21 14:18 Flyingis 阅读(789) | 评论 (0)编辑 收藏

中国企业对软件人才利用的思考

    作者:Flyingis

    刚刚看到一篇文章《中方落败软件人才争夺战 人才利用率堪忧》,里面谈及了大家经常讨论的话题,中国软件和印度软件的差距。这是一个老生常谈的话题了,经常看到各大媒体网站杂志报道类似的主题文章,对其中的缘由也分析的淋漓尽致,但在实际中始终没有改进,好像国外的高端电子产品到国内销售有一段滞后期,而许多已经被证明是先进的管理经营经验在国内应用难道也要经历一段酝酿的时期吗?下面是这篇文章的链接:

中方落败软件人才争夺战 人才利用率堪忧(一)

中方落败软件人才争夺战 人才利用率堪忧(二)

    这让我想到了一件事情。前几年在大学里,大家都认为计算机科学与技术是热门专业,许多优秀的考生都是非计算机不报,都想进入这个金牌领域,抱住这个金饭碗,但实际情况是什么呢,在一般情况下,当大多数人发现一门学科是热门专业的时候,其实这门学科很可能已经开始走下坡路了,或者是说,你现在考进去等到毕业的时候,很有可能不会像现在的毕业生这么风光,不仅单位公司抢着要,并且各个都是高薪高福利,让人羡慕。想想做生意的,当一家理发店在一条街上开始营业,生意火爆,让大家都开始把眼球注意到这条街的商业价值上,然后纷纷开店的时候,你会发现,最佳的赚钱机会已经被抢走了,虽然在初期没有什么影响,但是到了这条街上已经开了许多家理发店的时候,你若还想在这里挖到一桶金,已经不是那么容易了。这些都是我们生活中很简单很平常的事情,但经常被我们忽略。

    中国软件公司要像印度一样合理利用人才,对于大多数而言,的确非常困难,因为很多中小型都是在有项目才会招人,而有项目的时候往往又没有合适的或者充足的开发人员可以利用,这样造成了经常加班,开发人员不能专心某领域的研究,工作情绪不稳定的情况。另外,某些中小型公司老板可能总是认为现在每年毕业的软件人才过剩,不用担心找不到人来工作,而临时组成的团队却不能提供最优质的软件与服务,甚至频繁出现不能按期交付安装,一拖再拖的情况。本来想写的更多一些,但说到这里,大家可能会根据自己的实际情况想到更多,所以我回到上面举的几个例子,当中国企业已经认识到和印度软件业差距所在的时候,为什么没有人愿意试着去学习,去培养自己的人才,去完善人才管理,去营造一个良好的人才循环升级培养的氛围呢?特别是有一定实力与经济基础的中型或中大型公司。的确,中国有华为等几家著名的软件公司,但是对于中国偌大一个国家,有着这么多丰富的人才资源的国家来说,这样的公司实在太少太少,为什么这么多公司都不愿做建立合理软件人才培养梯队的先锋呢?就像我前面举出的例子一样,最先放弃急功近利的,按照一种人性化理念去经营的公司,才能获得最大的后期收益,等其它公司看着你眼红,想开始效仿你的时候,你的公司形象已经形成一种强有力的品牌,步入可持续发展的道路。

    我还没有做过企业的管理者,市场经济中的意识形态,国内的形势政策以及其它多种因素都会限制着国内软件公司的发展,“不当家不知道柴米油盐贵”。但是,作为一名旁观者,我希望能给中国软件业注入清醒的一针,而我知道仅仅这一针根本不能治愈中国软件业的“病”,仅希望大家特别是管理者都能尽一点微薄之力,慢慢改进。

posted @ 2005-11-21 14:08 Flyingis 阅读(1023) | 评论 (2)编辑 收藏

Struts Action的多种角色

    作者:Flyingis

    Action类是用户请求和业务逻辑之间的桥梁。每个Action充当用户的一项业务代理。在RequestProcessor类预处理请求时,在创建了Action的实例后,就调用自身的processActionPerform()方法,该方法再调用Action类的execute()方法。Action的execute()方法调用模型的业务方法,完成用户请求的业务逻辑,然后根据执行结果把请求转发给其他合适的Web组件。在实际的应用中,主要有以下几种比较常见的使用方法:

1.普通的Action应用

<action path="/normalAction"
type="package.OneActionClass">
name="oneForm"
input="page.jsp"
<forward name="success" path="success.jsp"/>
<forward name="failure" path="failure.jsp"/>
</action>

    Struts的ActionServlet接收到一个请求,然后根据struts-config.xml的配置定位到相应的mapping(映射);接下来如果form的范围是request或者在定义的范围中找不到这个form,创建一个新的form实例,如果找到则重用;取得form实例以后,调用其reset()方法,然后将表单中的参数放入form,如果validate属性不为false,调用validate()方法;如果validate()返回非空的ActionErrors,将会被转到input属性指定的URI,如果返回空的ActionErrors,那么执行Action的execute()方法,根据返回的ActionForward确定目标URI。即execute()仅当validate()成功以后才执行;input属性指定的是一个URI。


2.有Form的Action应用

<action path="/formAction"
type="org.apache.struts.actions.ForwardAction"
name="oneForm"
input="page.jsp"
parameter="another.jsp"
/>

    Struts会在定义的scope搜寻oneForm,如果找到则重用,如果找不到则新建一个实例;取得form实例以后,调用其reset()方法,然后将表单中的参数放入form,如果validate属性不为false,调用validate()方法;如果validate()返回非空的ActionErrors,将会被转到input属性指定的URI,如果返回空的ActionErrors,那么转到parameter属性指定的目标URI。

    这种方法使得没有action类可以存放我们的业务逻辑,所以所有需要写入的逻辑都只能写到form的reset()或者validate()方法中。validate()的作用是验证和访问业务层。因为这里的action映射不包括forward,所以不能重定向,只能用默认的那个forward。这种仅有form的action可以用来处理数据获取并forward到另一个JSP来显示。


3.仅有Action的Action应用

<action path="/actionAction"
type="package.OneActionClass">
input="page.jsp"
<forward name="success" path="success.jsp"/>
<forward name="failure" path="failure.jsp"/>
</action>

    ActionServlet接收到请求后,取得action类实例,调用execute()方法;然后根据返回的ActionForward在配置中找forward,forward到指定的URI或action。这样就没有form实例被传入execute()方法,于是execute()必须自己从请求中获取参数。Action可以被forward或者重定向。这种action不能处理通过HTML FORM提交的请求,只能处理链接式的请求。


4.仅有JSP的Action应用

<action path="/jspAction"
type="org.apache.struts.actions.ForwardAction"
parameter="another.jsp"
/>

    ActionServlet接到请求后调用ForwardAction的execute()方法,execute()根据配置的parameter属性值来forward到那个URI。这种情况下,没有任何form被实例化,比较现实的情形可能是form在request更高级别的范围中定义;或者这个action被用作在应用程序编译好后充当系统参数,只需要更改这个配置文件而不需要重新编译系统。


5.两个Action对应一个Form(和第四种方式部分的Action作用相近)

<action path="/oneAction"
type="package.OneActionClass">
name="oneForm"
input="one.jsp"
<forward name="success" path="/anotherAction.do"/>
</action>
<action path="/anotherAction"
type="package.AnotherActionClass">
name="oneForm"
input="another.jsp"
<forward name="success" path="success.jsp"/>
</action>

    这个组合模式可以被用来传递form对象,就每个单独的action来讲,处理上并没有和完整的action有什么实质的区别。需要注意的是在后一个action中同样会调用form的reset()和validate()方法,因此我们必须确保form中的信息不被重写。这种情况分两种方式处理:a) 在request中放入一个指示器表明前一个action有意向后一个action传递form,从而在后一个action可以保留那个form中的值,这一方式只能在使用forward时使用。b) 当使用redirect而不是forward时,可以把指示器放在session或更高的级别,在命令链的最后一环将这个指示器清除。


6.两个Action对应两个form

<action path="/oneAction"
type="package.oneActionClass">
name="oneForm"
input="one.jsp"
<forward name="successful" path="/anotherAction.do" redirect="true"/>
</action>
<action path="/anotherAction"
type="package.AnotherActionClass">"
name="anotherForm"
input="another.jsp"
<forward name="success" path="success.jsp"/>
</action>

    这个组合方式跟前一种在流程上没有太大区别,只是我们现在对于两个action分别提供了form,于是代码看上去更加清晰。于是我们可以分别处理WEB应用程序的输入和输出。值得注意的是,后一个action同样会尝试往form中写入那些参数,不过我们可以这样处理:a) 在后一个form中使用另一套属性名;b) 只提供getter而不提供setter。

基本处理过程:
    前一个action接收输入、验证、然后将数据写入业务层或持久层,重定向到后一个action,后一个action手动的从业务层/持久层取出数据,写入form(通过其他方式),交给前台JSP显示。这样做的好处是不必保留输入form中的值,因此可以使用redirect而不是forward。这样就降低了两个action之间的耦合度,同时也避免了不必要的重复提交。

注明:文中所提及的“仅有Form”指的是没有继承Struts提供的Action类,而是直接使用了Struts自身提供的Action类;“仅有Action”指的是仅继承了Struts提供的Action类而没有使用Form。

posted @ 2005-11-18 17:10 Flyingis 阅读(3629) | 评论 (2)编辑 收藏

Web开发2005年,情理之中、预料之外[转载]

(文章转自CSDN)

Web开发领域的2005年,一方面ASP.NET 2.0、PHP 5.1预期发布,另一方面Perl 6“已经开始看起来像个没有结束的项目了”,此外,Ajax和Ruby On Rails(简称RoR)的火爆让人嫉妒,这些现象的背后正是Web开发的理念悄然发生了变化。

  Web标准日渐流行

  当Jeffrey Zeldman在2003年出版《Designing With Web Standards》的时候,CSS已经被主流浏览器支持了4年之久。Web标准其实分三方面:结构化标准语言主要包括XHTML和XML,表现标准语言主要包括CSS,行为标准主要包括对象模型(如W3C DOM)、ECMAScript等。他的的主要好处在于缩小了页面大小、布局更加随意、也有利于页面和代码的分离,正是这些好处让微软MSN、网易、阿里巴巴和CSDN等网站在2005年陆续按照Web标准进行了重构。

  Ajax:用户体验型的富客户端技术

  用过微软Live服务的用户都为网络程序能随意拖动和放置页面栏目、无刷新更新网页数据、渐变的颜色处理感到吃惊,这些“酷”的技术被冠名为Ajax,这项技术最早由Google应用在GoogleMap和GoogleMail中,其实Ajax并不神奇,原理是通过调用XmlHttpRequest实现与服务器的异步通讯,并使用对应平台的XmlDom对返回的Xml消息进行处理,然后再通过DOM对页面中的HTML元素的操作实现丰富的、友好的用户界面。这和当初微软推广的Remote Scripting几乎如出一辙。不过,和当初不同的事,这项技术得到了足够的重视,相关开发包源源不断,成为2005最具亮丽的一道风景线,微软也耐不住寂寞,即将推出Atlas就是用来帮助开发者更容易地构建Ajax站点。Ajax的风行说明用户对于丰富的Web体验的需求日益增长,这种趋势不可逆转。

  RoR预示轻型开发框架的流行

  RoR是基于Ruby语言的轻型Web开发框架,不仅开发效率高(部署容易)、功能丰富(支持Ajax等流行应用) ,不可思议的是,他的性能比基于Struts和Hibernate的Java应用还高15%-30%。目前,其他语言也已经有类似的框架,如基于Python的Django、PHP的Cake、ASP.NET的Castle等等。Web应用特点是需求变化非常快,Rails提倡的“约定强于配置”的理念正好迎合了这种发展潮流。不过,使用RoR的大型网站还不多见,是否经得起考验,还看2006年。

  Web开发的2005年,我们还应当关注的是:

  ASP.NET 2.0随NET Framework 2.0发布

  每个ASP.NET程序员需要关注的产品。虽然不是一个革命性的升级,很多新特性还是足够让开发者心动。有了2.0,谁还愿意使用1.x?微软的产品总是让人对他产生依赖。

  Jdon Framework

  这个由国人彭晨阳开发的中小型J2EE应用系统的快速开发框架已经发布了1.3版本,和RoR类似,Jdon框架中, Action的CRUD功能实现是由配置文件实现的,一般情况下无需编码。支持日本的Ruby,不如支持中国的Jdon,你们觉得呢?

posted @ 2005-11-17 21:49 Flyingis 阅读(737) | 评论 (0)编辑 收藏

Hibernate学习心得--性能优化

    作者:Flyingis
    
    在使用Hibernate进行查询的时候大家都会用到Hibernate缓存,其中Session缓存即一块内存空间,存放了相互关联的Java对象,这些位于Session缓存中的对象就是持久化对象,Session根据持久化对象的状态变化来同步更新数据库。这个Session缓存是Hibernate的一级缓存。此外,SessionFactory有一个内置缓存和一个外置缓存,即Hibernate的第二级缓存。而Hibernate正是由于这些缓存的存在,才使得其数据库操作效率提高,就是说,在提供了方便易操作的操作数据库数据的方式的同时保证了工作效率,但是不能因此而免去后顾之忧,需要在设计业务逻辑层的时候考虑使用最优的架构,节省有效的系统资源。在查询方面,Hibernate主要从以下几个方面来优化查询性能:

1.降低访问数据库的频率,减少select语句的数目。实现手段包括:

    使用迫切左外连接或迫切内连接检索策略。
    对延迟检索或立即检索策略设置批量检索数目。
    使用查询缓存。

2.避免多余加载程序不需要访问的数据。实现手段包括:

    使用延迟检索策略。
    使用集合过滤。

3.避免报表查询数据占用缓存。实现手段为利用投影查询功能,查询出实体的部分属性。

4.减少select语句中的字段,从而降低访问数据库的数据量。实现手段为利用Query的iterate()方法。

    在插入和更新数据时,要控制insert和update语句,合理设置映射属性来保证插入更新的性能,例如,当表中包含许多字段时,建议把dynamic-update属性和dynamic-update属性都设为true,这样在insert和update语句中就只包含需要插入或更新的字段,这可以节省数据库执行SQL语句的时间,从而提高应用的运行性能。

    还有什么其它的提升性能的方式希望和大家一起讨论。

posted @ 2005-11-15 10:22 Flyingis 阅读(6157) | 评论 (3)编辑 收藏

Hibernate学习心得--映射对象标识符

    作者:Flyingis

    在关系数据库中的主键可分为自然主键(具有业务含义)和代理主键(不具有业务含义),其中代理主键可以适应不断变化的业务需求,因此更加流行。代理主键通常为整数类型,与此对应,在持久化类中野应该把OID定义为整数类型,Hibernate允许把OID定义为short、int和long类型,以及它们的包装类型。

    Hibernate提供了几种内置标识符生成器,每一种标识符生成器都有它的使用范围,应该根据所使用的数据库和Hibernate应用的软件架构来选择合适的标识符生成器。下面是几种常用数据库系统可使用的标识符生成器:

MYSQL: identity increment hilo native
MS SQL Server: identity increment hilo native
Oracle: sequence seqhilo hilo increment native
夸平台开发: native

    OID是为持久化层服务的,它不具备业务含义,而域对象位于业务逻辑层,用来描述业务模型。因此,在域对象中强行加入不具备业务含义的OID,可以看作是持久化层对业务逻辑层的一种渗透,但这种渗透是不可避免的,否则Hibernate就无法建立缓存中的对象与数据库中记录的对应关系。

    当然,映射中还包括自然主键的映射方案。对于从头设计的关系数据库模型,应该优先考虑使用代理主键。

posted @ 2005-11-14 10:43 Flyingis 阅读(686) | 评论 (0)编辑 收藏

Hibernate学习心得--Hibernate最简单的描述

    作者:Flyingis

    在网上很多文章和论坛都在讨论Hibernate,初次接触Hibernate,当然需要知道它是什么,可以用来做什么。用简单的语言来描述,可以认为Hibernate是:

    它是连接Java应用程序和关系数据库的中间件。
    它对JDBC API进行了封装,负责Java对象的持久化。
    在分层的软件架构中它位于持久花层,封装了所有数据访问细节,使业务逻辑层可以专注于实现业务逻辑。
    它是一种ORM(Object-Relation Mapping)映射工具,能够建立面向对象的域模型和关系数据库模型之间的映射。

    在Java应用中使用Hibernate包含以下步骤:

1.创建Hibernate的配置文件。
2.创建持久化类。
3.创建对象-关系映射文件。
4.通过Hibernate API编写访问数据库的代码。

posted @ 2005-11-13 13:14 Flyingis 阅读(693) | 评论 (0)编辑 收藏

Hibernate 2 升级为Hibernate 3 的注意事项[转载]

目的,主要是那当前的项目练手,熟悉一下hibernate2和hibernate3的差别,给当前项目一点扩展的空间。

1.首先将hibernate2.jar替换为hibernate3.jar(hibernate-3.0.5)
  hibernate-tools.jar也替换成新的(从hibernate-tools-3.0.0.alpha4a找出来的)

2.将所有程序中的net.sf.hibernate替换为org.hibernate.
 
3.但是有例外
  net.sf.hibernate.expression.Expression换为org.hibernate.criterion.Expression
  如果用eclipse,用ctrl+shift+o快捷键可以加快速度
 
4.在使用hql查询时将
  createSQLQuery(hql,"c",EZCampaignDTO.class);改为createSQLQuery(hql).addEntity("c",EZCampaignDTO.class);
 
5.在批量插入时
  将原来的int size = ((SessionFactoryImpl)(session.getSessionFactory())).getJdbcBatchSize()
  改为int size = ((SessionFactoryImpl)(session.getSessionFactory())).getSettings().getJdbcBatchSize();
 
6.在计算count时
  将原来的int size = ((Integer) session.iterate(hql).next()).intValue();
  改为int size = ((Integer) session.createQuery(hql).iterate().next()).intValue();
其中hql="select count(*) from " + DAOVar.contactClass;
 
7.还有就是把.hbm中的hibernate-mapping-2.0.dtd替换为hibernate-mapping-3.0.dtd
  Hibernate Mapping DTD 2.0替换为Hibernate Mapping DTD 3.0
 
8.hibernate.cfg.xml中
  Hibernate Mapping DTD 2.0替换为Hibernate Mapping DTD 3.0
  <property name="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</property>
 
9.hibernate.properties中类似
 
10.cache-config.xml中
   <provider className="net.sf.hibernate.cache.OSCacheProvider"/>替换为
   <provider className="org.hibernate.cache.OSCacheProvider"/>
 
11.classeshibernate.properties中
   hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider
   hibernate.dialect=org.hibernate.dialect.SQLServerDialect
 
12.在自动外部模块部分有一个功能是根据模版自动生成.hbm文件在load,结果出来的.hbm中有问题:
   生成的 <composite-id unsaved-value="any" mapped="false">其中mapped="false" 出错。找了半天才发现在网上的hibernate-mapping-3.0.dtd文件有支持mapped="false"这个属性。而本地的hebernate3.0.5中的hibernate-mapping-3.0.dtd文件没有这个属性。晕,hibernate也太不负责了吧。解决办法把hibernate-mapping-3.0.dtd copy到jboss\bin目录下然后,在template文件中<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "hibernate-mapping-3.0.dtd">,然后他会在jboss\bin目录下读取该文件。
 
13.重新测试,还是咣铛,发现子类读父类数据时抛出异常:
   "org.hibernate.LazyInitializationException: could not initialize proxy"
   延迟抓取出的错,hb3对many-to-one的默认处理是lazy = "proxy",没有搞懂到底怎么回事,把所有many-to-one,one-to-one都加上lazy="false",再测试终于大功告成。

文章原作者Blog:
::URL::http://blog.csdn.net/chinaewolf/

posted @ 2005-11-12 19:29 Flyingis 阅读(1203) | 评论 (0)编辑 收藏

Hibernate学习心得--软件设计阶段的模型

    作者:Flyingis

    在科学和工程技术领域,模型是一个很有用途的概念,它可以用来模拟一个真实的系统。在软件开发领域,模型用来表示真实世界的实体。在软件开发的不同阶段,需要为目标系统创建不同类型的模型。在分析阶段,需要创建概念模型。在设计阶段,需要创建域模型和数据模型。其中,域模型是面向对象的,数据模型是面向关系的,域模型和数据模型之间存在一种对象-关系映射。

概念模型

    概念模型清楚地显示了问题域中的实体。不管是技术人员还是非技术人员都能看得懂改面模型,他们可以很容易地提出模型中存在的问题,帮助分析人员及早对模型进行修改。在软件设计域开发周期中,模型的变更需求提出得越晚,所耗费得开发成本就越大。

    概念模型描述了每个实体得概念和属性,以及实体之间的关系:一对一、一对多和多对多。在现实生活中都可以找到相应的例子,例如一只母鸡有很多小鸡是一对多关系,一位客户选购了很多商品,而这些商品也可以被许多客户选购,这是多对多关系。

关系数据模型

    到目前为止,关系数据库仍然是使用最广泛的数据库,它存储的是关系数据。关系数据模型是在概念模型的基础上建立起来的,用于描述这些关系数据的静态结构,它由以下内容组成:

    一个或多个表
    表的所有索引
    视图
    触发器
    表与表之间的参照完整性

    数据库Schema是对数据模型的实现。对于支持SQL的关系数据库,可以采用SQL DDL语言来创建数据库Schema。SQL DDL 用于生成数据库中的物理实体,例如下面的创建CUSTOMERS表的 SQL DDL:

    create table CUSTOMERS {
      ID int not null,
      NAME varchar(20),
      AGE int,
      primary key (ID)
    };

    值得注意的是,数据库Schema有两种含义,一种是概念上的Schema,指的是一组DDL语句集,该语句集完整地描述了数据库的结构。还有一种是物理上的Schema,指的是数据库中的一个名字空间,它包含一组表、视图和存储过程等命名对象。物理Schema可以通过标准SQL语句来创建、更新和修改。例如以下SQL语句创建了两个物理Schema:

    create schema SCHEMA_A;
    create table SCHEMA_A.CUSTOMERS(ID int not null,……);

    create schema SCHEMA_B;
    create table SCHEMA_B.CUSTOMERS(ID int not null,……);

域模型

    域模型由以下内容组成:具有状态和行为的域对象;域对象之间的关系。

域对象

1.实体域对象:代表人、地点、事物或概念。通常,可以把业务领域中的名词,例如客户、订单、商品,当然也包括前面提到过的母鸡,作为实体域对象;
2.过程域对象:代表应用中的业务逻辑或流程。它通常依赖于实体域对象。
3.事件域对象:代表应用中的一些事件,例如异常、警告或超时等。

域对象之间的关系

    在域模型中,类之间存在四种关系。

1.关联(Association)
   
    关联指的是类之间的引用关系,这是实体域对象之间最普遍的一种关系。关联可以分为一对一、一对多和多对多关联。

2.依赖(Dependency)

    依赖指的是类之间的访问关系。如果类A访问类B的属性或方法,或者说是A负责实例化B,那么可以说类A依赖类B。

3.聚集(Aggregation)

    聚集指的是整体与部分之间的关系,在实体域对象之间也很常见。例如,人与手就是聚集关系,在Person类中由一个hands集合,它存放被聚集的Hand对象:

    public class Person {
      private Set hands = new HashSet();
      …………
    }

4.一般化(Generalization)

    一般化指的是类之间的继承关系。

域对象的持久化概念

    当实体域对象在内存中创建后,它们不可能永远存在。最后,他们要么从内存中清除,要么被持久化到数据存储库中。内存无法永久地保存数据,因此必须对实体域对象进行持久化。否则,如果对象没有被持久化,用户在应用运行时创建地订单信息将在应用结束运行后随之消失。

    当然,并不是所有地域对象都需要持久化,通常只有实体域对象才需要持久化,另外,有些实体域对象也不需要持久化。

    狭义的理解,“持久化”仅仅指把域对象永久保存到数据库中;广义的理解,“持久化”包括和数据库相关的各种操作。

   参考书籍:孙卫琴 精通Hibernate Java对象持久化技术详解

posted @ 2005-11-12 19:14 Flyingis 阅读(2529) | 评论 (0)编辑 收藏

这几天BlogJava一直在默默的变化

    就在前一个小时左右的时间博客排行榜上列出的都是前200位博客,现在已经和博客园主页上一样只列出前100位了(我现在恰好是101位)。其实100或200不是最主要的,关键是这里所倡导的原创意识、竞争意识可以促进BlogJava不断完善和发展。这段时间发现BlogJava变化还是挺大的,我在这里定居时间不长,不知道以前怎么样,但这几天我至少看到了首页上加入了“24小时最热随笔”、“最近更新博客”、“最新注册博客”,还有今天排行榜上的变化,这些都让我对这里充满了期待,在这里和大家一起学习,共同发展。

posted @ 2005-11-09 17:05 Flyingis 阅读(647) | 评论 (2)编辑 收藏

JSF VS Tapestry 全面比较

    作者:Flyingis

    Java不像微软拥有Visual Studio 2005,各个开发组件无缝整合,提供高效的开发与部署环境。开发环境、插件和工具的多样化,给Java开发者带来了一些麻烦,但是却换来了极大的灵活性和选择的空间。Eclipse已经逐渐成为业界首选的开发环境,给Borland等公司带来不少的冲击,使得老牌的Java IDE公司的市场份额逐渐丢失,而在应用服务器、对象关系数据中间件、报表中间件、Web开发框架等领域仍然是热闹非凡,选择众多。

    Java Web开发框架主要有Struts/JSF/Tapestry/WebWork/Spring等,它们都非常优秀,有自己的优点与不足,对于我们开发者而言,只选对的,适合项目需求的才是最重要的。这里有一篇文章介绍了JSF和Tapestry之间的相似之处与不同点,可以让我们更好的认识到它们之中哪种框架更适合你。

JSF VS Tapestry 全面比较(一)
JSF VS Tapestry 全面比较(二)
JSF VS Tapestry 全面比较(三)

posted @ 2005-11-09 13:08 Flyingis 阅读(1835) | 评论 (0)编辑 收藏

挖掘Jakarta Commons中隐藏的宝贝(三)[转载]

(文章转自CSDN)

3. 使用XPath语法来查询对象和集合

Commons JXPath是一种让人很吃惊地(非标准的)对XML标准的使用。XPath一段时间以来一直是作为在一个XSL样式表中选择结点或结点集的一种方法。如果你用过XML,你会很熟悉用这样的语法/foo/bar来从foo文档元素中选择bar子元素。

Jakarta Commons JXPath增加了一种有趣的手法:你可以用JXPath来从bean和集合中选择对象,其中如servlet上下文和DOM文档对象。考虑一个包含了Person对象的列表。每一个Person对象有一个属性的类型为Job,每一个Job对象有一个salary(薪水)属性,类型为int。Person对象也有一个coountry属性,它是两个字符的国家代码。使用JXPath,你可以很容易地选出所有国家为美国,薪水超过一百万美元的Person对象。下面是设置一个由JXPath过滤地bean的List的代码:

// Person的构造器设置姓和国家代码
Person person1 = new Person( "Tim", "US" );
Person person2 = new Person( "John", "US" );
Person person3 = new Person( "Al",  "US" );
Person person4 = new Person( "Tony", "GB" );

// Job的构造器设工作名称和薪水
person1.setJob( new Job( "Developer", 40000 ) );
person2.setJob( new Job( "Senator", 150000 ) );
person3.setJob( new Job( "Comedian", 3400302 ) );
person4.setJob( new Job( "Minister", 2000000 ) );

Person[] personArr =
  new Person[] { person1, person2,
                 person3, person4 };

List people = Arrays.asList( personArr );


people List包含了四个bean: Tim, John, Al, 和George。Tim是一个挣4万美元的开发者,John是一个挣15万美元的参议员,Al是一个挣340万美元的喜剧演员,Tony是一个挣200万欧元的部长。我们的任务很简单:遍历这个List,打印出每一个挣钱超过100百万美元的美国公民的名字。记住people是一个由Person对象构成的ArrayList,让我们先看一下没有利用JXPath便利的解决方案:

Iterator peopleIter = people.getIterator();
while( peopleIter.hasNext() ) {
  Person person = (Person) peopleIter.next();

  if( person.getCountry() != null &&
      person.getCountry().equals( "US" ) &&
      person.getJob() != null &&
      person.getJob().getSalary() > 1000000 ) {
        print( person.getFirstName() + " "
               person.getLastName() );
      }
    }
  }
}


上面的例子是繁重的,并有些容易犯错。为了发现合适的Person对象,你必须首先遍历每一个Person对象并且检查conuntry的属性。如果country属性不为空并且符合要求,那么你就要检查job属性并看一下它是否不为空并且salary属性的值大于100万。上面的例子的代码行数可以被Java 1.5的语法大大减少,但是,哪怕是Java 1.5,你仍旧需要在两层上作两次比较。

如果你想对内存中的一组Person对象也做一些这样的查询呢?如果你的应用想显示所有在英格兰的名叫Tony的人呢?喔,如果你打印出每一个薪水少于2万的工作的名称呢?

如果你将这些对象存储到关系数据库中,你可以用一个SQL查询来解决问题,但你正在处理的是内存中的对象,你可以不必那么奢侈。虽然XPath主要是用在XML上面,但你可以用它来写一个针对对象集合的“查询”,将对象作为元素和,把bean属性作为子元素。是的,这是一种对XPath奇怪的应用,但请先看一下下面的例子如何在people上,一个由Person对象构成的ArrayList,实现这三种查询:

import org.apache.commons.jxpath.JXPathContext;

public List queryCollection(String xpath,
                            Collection col) {
    List results = new ArrayList();

    JXPathContext context =
        JXPathContext.newContext( col );

    Iterator matching =
        context.iterate( xpath );

    while( matching.hasNext() ) {
        results.add( matching.getNext() );
    }
    return results;
}

String query1 =
   ".[@country = 'US']/job[@salary > 1000000]/..";  
String query2 =
   ".[@country = 'GB' and @name = 'Tony']";  
String query3 =
   "./job/name";

List richUsPeople =
    queryCollection( query1, people );
List britishTony =
    queryCollection( query2, people );
List jobNames =
    queryCollection( query3, people );



queryCollection()方法使用了一个XPath表达式,将它应用到一个集合上。XPath表达式被JXPathContext求值, JXPathContext由JXPathContext.newContext()调用创建,并将它传入要执行查询的集合中。凋用context.iterate()来在集合中的每一个元素上应用XPath表达式,返回包含所有符合条件的“节点”(这里是“对象”)的Iterator。上例中执行的第一个查询,query1,执行了和不使用JXPath的例子相同的查询。query2选择所有国家为GB并且名字属性为Tony的Person对象,query3返回了一个String对象的List,包含了所有Job对象的name属性。

当我第一次看到Commons JXPath, 它是一个坏思想的想法触动了我。为什么要把XPath表达式应用到对象上?有点感觉不对。把XPath作为一个bean的集合的查询语言的这种意想不到的用法,在过去几年中已经好多次给我带来了便利。如果你发现你在list中循环来查找符合条件的元素,请考虑一下JXPath。更多的信息,请参考Jakarta Commons Cookbook的第12章,“查找和过滤”,它讨论了Commons JXPath和与Commons Digester配对的Jakarta Lucene。

还有更多
对Jakarta Commons纵深地探索仍然在调试中。在这一系列的下面几部分中,我会介绍一些相关的工具和功能。在Commons Collections中设置操作,在collection中使用Predicate对象,使用Commons Configuration来配置一个应用和使用Commons Betwixt来读写XML。能从Jakarta Commons得到的东西还有很多,不能在几千字中表达,所以我建议你看一下Jakarta Commons Cookbook。许多功能可能会,一眼看上去,有点普通,但Jakarta Commons的能量就蕴藏在这些工具的相互组合和与你的系统的集成当中。

Timothy M. O'Brien是一个专业的独立的开发者,在Chicago地区工作和生活。

资源
·onjava.com:
onjava.com
·Matrix-Java开发者社区:http://www.matrix.org.cn/
·APACHE:APACHE.org

posted @ 2005-11-09 12:27 Flyingis 阅读(832) | 评论 (0)编辑 收藏

挖掘Jakarta Commons中隐藏的宝贝(二)[转载]

(文章转自CSDN)

2.Commons Collections中的算子

算子成为Commons Collections 3.1中的有趣的部分有两个原因:它们没有得到应得的重视并且它们有改变你编程的方式的潜力。算子只是一个奇特的名字,它代表了一个包装了函数的对象—一个“函数对象”。当然,它们不是一回事。如果你曾经使用过C和C++的方法指针,你就会理解算子的威力。
一个算子是一个对象—一个Predicate,一个Closure, 一个Transformer。

Predicates求对象的值并返回一个boolean,Transformer求对象的值并返回新对象,Closure接受对象并执行代码。算子可以被组合成组合算子来模仿循环,逻辑表达式,和控制结构,并且算子也可以被用来过滤和操作集合中的元素。在这么短的篇幅中解释清楚算子是不可能的,所以跳过介绍,我将会通过使用和不使用算子来解决同一问题(解释算子)。在这个例子中,从一个ArrayList中而来的Student对象会被排序到两个List中,如果他们符合某种标准的话。

成绩为A的学生会被加到honorRollStudents(光荣榜)中,得D和F的学生被加到problemStudents (问题学生)list中。学生分开以后,系统将会遍历每个list,给加入到光荣榜中学生一个奖励,并安排与问题学生的家长谈话的时间表。下面的代码不使用算子实现了这个过程:

List allStudents = getAllStudents();

// 创建两个ArrayList来存放荣誉学生和问题学生
List honorRollStudents = new ArrayList();
List problemStudents = new ArrayList();

// 遍历所有学生,将荣誉学生放入一个List,问题学生放入另一个
Iterator allStudentsIter = allStudents.iterator();
while( allStudentsIter.hasNext() ) {
  Student s = (Student) allStudentsIter.next();

  if( s.getGrade().equals( "A" ) ) {
    honorRollStudents.add( s );
  } else if( s.getGrade().equals( "B" ) &&
             s.getAttendance() == PERFECT) {
    honorRollStudents.add( s );
  } else if( s.getGrade().equals( "D" ) ||
             s.getGrade().equals( "F" ) ) {
    problemStudents.add( s );
  } else if( s.getStatus() == SUSPENDED ) {
    problemStudents.add( s );
  }
}

// 对于的有荣誉学生,增加一个奖励并存储到数据库中
Iterator honorRollIter =
    honorRollStudents.iterator();
while( honorRollIter.hasNext() ) {
  Student s = (Student) honorRollIter.next();
  
// 给学生记录增加一个奖励
  s.addAward( "honor roll", 2005 );
  Database.saveStudent( s );
}

// 对所有问题学生,增加一个注释并存储到数据库中
Iterator problemIter = problemStudents.iterator();
while( problemIter.hasNext() ) {
  Student s = (Student) problemIter.next();

  // 将学生标记为需特殊注意
  s.addNote( "talk to student", 2005 );
  s.addNote( "meeting with parents", 2005 );
  Database.saveStudent( s );
}


上述例子是非常过程化的;要想知道Student对象发生了什么事必须遍历每一行代码。例子的第一部分是基于成绩和考勤对Student对象进行逻辑判断。

第二部分对Student对象进行操作并存储到数据库中。像上述这个有着50行代码程序也是大多程序所开始的—可管理的过程化的复杂性。但是当需求变化时,问题出现了。一旦判断逻辑改变,你就需要在第一部分中增加更多的逻辑表达式。

举例来说,如果一个有着成绩B和良好出勤记录,但有五次以上的留堂记录的学生被判定为问题学生,那么你的逻辑表达式将会如何处理?或者对于第二部分中,只有在上一年度不是问题学生的学生才能进入光荣榜的话,如何处理?当例外和需求开始改变进而影响到过程代码时,可管理的复杂性就会变成不可维护的面条式的代码。

从上面的例子中回来,考虑一下那段代码到底在做什么。它在一个List遍历每一个对象,检查标准,如果适用该标准,对此对象进行某些操作。上述例子可以进行改进的关键一处在于从代码中将标准与动作解藕开来。下面的两处代码引用以一种非常不同的方法解决了上述的问题。首先,荣誉榜和问题学生的标准被两个Predicate对象模型化了,并且加之于荣誉学生和问题学生上的动作也被两个Closure对象模型化了。这四个对象如下定义:

import org.apache.commons.collections.Closure;
import org.apache.commons.collections.Predicate;

// 匿名的Predicate决定一个学生是否加入荣誉榜
Predicate isHonorRoll = new Predicate() {
  public boolean evaluate(Object object) {
    Student s = (Student) object;

    return( ( s.getGrade().equals( "A" ) ) ||
            ( s.getGrade().equals( "B" ) &&
              s.getAttendance() == PERFECT ) );
  }
};

//匿名的Predicate决定一个学生是否是问题学生
Predicate isProblem = new Predicate() {
  public boolean evaluate(Object object) {
    Student s = (Student) object;

    return ( ( s.getGrade().equals( "D" ) ||
               s.getGrade().equals( "F" ) ) ||
             s.getStatus() == SUSPENDED );
  }
};

//匿名的Closure将一个学生加入荣誉榜
Closure addToHonorRoll = new Closure() {
  public void execute(Object object) {
    Student s = (Student) object;
      
// 对学生增加一个荣誉记录
    s.addAward( "honor roll", 2005 );
    Database.saveStudent( s );
  }
};

// 匿名的Closure将学生标记为需特殊注意
Closure flagForAttention = new Closure() {
  public void execute(Object object) {
    Student s = (Student) object;
      
// 标记学生为需特殊注意
    s.addNote( "talk to student", 2005 );
    s.addNote( "meeting with parents", 2005 );
    Database.saveStudent( s );
  }
};


这四个匿名的Predicate和Closure是从作为一个整体互相分离的。flagForAttention(标记为注意)并不知道什么是确定一个问题学生的标准 。现在需要的是将正确的Predicate和正确的Closure结合起来的方法,这将在下面的例子中展示:

import org.apache.commons.collections.ClosureUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.functors.NOPClosure;

Map predicateMap = new HashMap();

predicateMap.put( isHonorRoll, addToHonorRoll );
predicateMap.put( isProblem, flagForAttention );
predicateMap.put( null, ClosureUtils.nopClosure() );

Closure processStudents =
    ClosureUtils.switchClosure( predicateMap );

CollectionUtils.forAllDo( allStudents, processStudents );


在上面的代码中,predicateMap将Predicate与Closure进行了配对;如果一个学生满足作为键值的Predicate的条件,那么它将把它的值传到作为Map的值的Closure中。通过提供一个NOPClosure值和null键对,我们将把不符合任何Predicate条件的Student对象传给由ClosureUtils调用创建的“不做任何事”或者“无操作”的NOPClosure。

一个SwitchClosure, processStudents,从predicateMap中创建。并且通过使用CollectionUtils.forAllDo()方法,将processStudents Closure应用到allStudents中的每一个Student对象上。这是非常不一样的处理方法;记住,你并没有遍历任何队列。而是通过设置规则和因果关系,以及CollectionUtils和SwitchClosur来完成了这些操作。

当你将使用Predicate的标准与使用Closure的动作将分离开来时,你的代码的过程式处理就少了,而且更容易测试了。isHonorRoll Predicate能够与addToHonorRoll Closure分离开来进行独立的单元测试,它们也可以合起来通过使用Student类的模仿对象进行测试。第二个例子也会演示CollectionUtils.forAllDo(),它将一个Closure应用到了一个Collection的每一个元素中。

你也许注意到了使用算子并没用减少代码行数,实际上,使用算子还增加了代码量。但是,通过算子,你得到了将到了标准与动作的模块性与封装性的好处。如果你的代码题已经接近于几百行,那么请考虑一下更少过程化处理,更多面向对象的解决方案—通过使用算子。

Jakarta Commons Cookbook中的第四章“算子”介绍了Commons Collections中可用的算子,在第五章,“集合”中,向你展示了如何使用算子来操作Java 集合类API。

所有的算子-- Closure, Predicate, 和 Transformer—能够被合并为合并算子来处理任何种类的逻辑问题。switch, while和for结构能够被SwitchClosure, WhileClosure, 和 ForClosure模型化。
复合的逻辑表达式可以被多个Predicate构建,通过使用OrPredicate, AndPredicate, AllPredicate, 和 NonePredicate将它们相互联接。Commons BeanUtils也包含了算子的实现被用来将算子应用到bean的属性中-- BeanPredicate, BeanComparator, 和 BeanPropertyValueChangeClosure。算子是考虑底层的应用架构的不一样的方法,它们可以很好地改造你编码实现的方法。

>>>>下一篇

posted @ 2005-11-09 12:21 Flyingis 阅读(1120) | 评论 (0)编辑 收藏

挖掘Jakarta Commons中隐藏的宝贝(一)[转载]

(文章转自CSDN)

如果你不熟悉Jakarta Commons话,那么很有可能你已经重新发明了好几个轮子。在你编写更多的普通的框架或工具之前,体验一下Commons吧。它将会大大地节约你的时间。太多的人自己写一个,其实是与Commons Lang中的StringUtils重复的StringUtils类,或者,开发者不知道从Commons Collections中重新创建工具,哪怕commons-collections.jar已经在classpath中可用了。

真的,请停一下。看看Commons Collections API,然后再回到你的任务中;我发誓你会发现一些简单有用的东西可以帮你在明年节省一周的时间。如果大家花一点时间看看Jakarta Commons,我们将会得到更少的重复代码—我们将在重用的宗旨下真正做一些有用的事情。

我确实看到这样的情况发生过:一些人研究了一下Commons BeanUtils或者Commons Collections,然后总是有“啊,如果我那时知道这个的话,我就不会写那一万行的代码了”这样的时刻。Jakarta Commons仍有一部分保持相当的神秘;比如,许多人还没有听说过Commons CLI和Commons Configuration,并且大多数人还没有注意到Commons Collections中的functors(算子)包的价值。在这一系列中,我会专门强调一些Jakarta Commons中较少得到重视的工具和功能。

在这一系列的第一部分,我将探索定义在Commons Digester中的XML规则,Commons Collections中的功能,和使用一个有趣的应用,Commons JXPath,来查询一个对象的List。Jakarta Commons包含的功能目的在于帮助你解决低层次的编程问题:遍历集合,解析XML和从List中检出对象。我建议你花一些时间在这些小功能上,学习Jakarta Commons真的会为你节省不少时间。

并不简单地是学习使用Commons Digester来解析XML或者使用CollectionUtils的Predicate来过滤一个集合,而是当你一旦意识到如何将这些功能组合起来使用并且如何将Commons集成到你的项目中去的时候,你才会真正地看到它的好处。如果你这样做地话,你将会把commons-lang.jar, commons-beanutils.jar,和 commons-digester.jar当成JVM本身来看待。

如果你对Jakarta Commons更深的内容感兴趣的话,可以看一下Jakarta Commons Cookbook。这本书给你很多方法来更好的使用Commons,并告诉你如何将Jakarta Commons与其它的小的开源组件集成,如Velocity, FreeMarker, Lucene, 和 Jakarta Slide。这本书,我介绍了一组广泛的工具从Commons Lang中的简单工具到组合了Commons Digester, Commons Collections, 和Jakarta Lucene来搜索威廉.莎士比亚的著作。我希望这一系列和Jakarta Commons Cookbook这本书能够提供给你一些有趣的低层次的编程问题的解决方案。

1. 用于Commons Digester的基于XML的规则集
Commons Digester 1.6提供了将XML转化为对象的最简单的方法。Digester已经由O'Reilly网站上的两篇文章介绍过了:“学习和使用Jakarta Digester”,作者是Philipp K. Janert,和“使用Jakarta Commons, 第二部分”,作者是Vikram Goyal。两篇文章都演示了XML规则集的使用,但如何在XML中定义规则集并没有理解。大多所见到的Digester的使用是程序化地定义规则集,以已编译的形式。你应该避免硬编码的Digester规则,特别是当你可以将映射信息存储在外部文件中或一个类路径资源中时。外部化一个Digester规则可以更好地适应一个演化中的XML文档结构或者说一个演化中的对象模型。

为了演示在XML中定义规则集与硬编码的规则集之间的区别,考虑系统解析XML给一个Person bean,包括在下面定义的属性—id, name和age。

package org.test;

public class Person {
  public String id;
  public String name;
  public int age;
                
  public Person() {}

  public String getId() { return id; }
  public void setId(String id) {
    this.id = id;
  }

  public String getName() { return name; }
  public void setName(String name) {
    this.name = name;
  }

  public int getAge() { return age; }
  public void setAge(int age) {
    this.age = age;
  }
}


确认你的应用需要解析一个包含了多个person元素的XML文件。下面的XML文件,data.xml,包含了两个person元素,你想要把它们解析到Person对象中:


  
    Tom Higgins
    25
  

  
    Barney Smith
    75
  

  
    Susan Shields
    53
  



你希望如果结构和XML文件的内容在未来几个月中变化,你不需要在已编译的Java代码中硬编码XML文件的结构。为了做到这一点,你需要在一个XML文件中定义Digester的规则,并且它可以作为一种资源从类路径中装入。下面的XML文档,person-rules.xml,映射person元素到Person bean:

  
    
                          paramtype="java.lang.Object"/>
    
    
    
  



上述所做的是指示Digester创建一个新的Person实例,当它遇到一个person元素时,调用add()来将Person对象加入到一个ArrayList中,设置person元素中相匹配的属性,并从下一级元素name和age中设置name和age的属性。

现在你已经看到了Person类,会被解析的文档,和以XML的形式定义的Digester规则。现在你需要创建一个由person-rules.xml定义了规则的Digester的实例。下面的代码创建 了一个Digester,通过将person-rules.xml的URL传递给DigesterLoader

既然person-rules.xml文件是与解析它的类在同一个包内的类路径资源,URL可以通过getClass().getResource()来得到。DigesterLoader然后解析规则并将它加到新创建的Digester上:

import org.apache.commons.digester.Digester;
import org.apache.commons.digester.xmlrules.DigesterLoader;

// 从XML规则集中配置Digester
URL rules = getClass().getResource("./person-rules.xml");
Digester digester =
    DigesterLoader.createDigester(rules);

// 将空的List推入到Digester的堆栈
List people = new ArrayList();
digester.push( people );

// 解析XML文档
InputStream input = new FileInputStream( "data.xml" );
digester.parse( input );


一旦Digester完成对data.xml的解析,三个Person对象将会在ArrayList people中。
与将规则定义在XML不同的方法是使用简便的方法将它们加入到一个Digester实例中。大多数文章和例子都用这种方法,使用addObjectCreate() 和 addBeanPropertySetter()这样的方法来将规则加入中Digester上。下面的代码加入了与定义在person-rules.xml中相同的规则:

digester.addObjectCreate("people/person", Person.class);
digester.addSetNext("people/person", "add", "java.lang.Object");
digester.addBeanPropertySetter("people/person", "name");
digester.addBeanPropertySetter("people/person", "age");



如果你曾经发现自己正在用一个有着2500行代码的类,用SAX来解析一个巨大的XML文档,或者使用DOM或JDOM的完整的一个集合类,你就会理解XML的解析比它应该做的要复杂的多,就大多数情况来说。如果你正在建一个有着严格的速度和内存要求的高效的系统,你会需要SAX解析器的速度。如果你需要DOM级别3的复杂度,你会需要像Apache Xerces的解析器。但如果你只是简单的试图将几个XML文档解析到对象中去的话,看一下Commons Digester, 并把你的规则定义在一个XML文件中。

任何时候你都应该将配置信息从硬编码中移出来。我会建议你在一个XML文件中定义规则并从文件系统或类路径中装入它。这样可以使你的程序更好地适应XML文档以及对象模型的变化。有关在XML文件中定义Digester规则的更多的资料,参看Jakarta Commons Cookbook一书的6.2节,“将XML文档转换为对象”

>>>>下一章

posted @ 2005-11-09 12:18 Flyingis 阅读(815) | 评论 (0)编辑 收藏

用Java实现自动在数据库表中生成ID号(改进算法)[原创]

    作者:Flyingis

    在前面的一篇日志里面,我设计了在数据库表中自动生成ID号的一种算法(
点击这里查看),这个算法主要应用于字典表的修改中。字典表的ID号是这样设计的:A01、A05、A28等等,即一位字母+两位数字。由于每个字典表的ID号的第一个字母对于一个字典表来说是固定的,这样做的目的在于在其它表中查看数据的时候可以很容易分辨字典项的ID号是属于哪一个数据字典的,因此这就限制了每个字典表的数据不能超过99条,当数据量大于99条的时候,那个算法就不再适用。

    因此这里给出了一个改进的算法(其实只作了一点点改进),可以满足数据在1~999条之间的数据字典,这对于绝大多数应用来说已经是绰绰有余了。下面就给出具体的方法:

/* 
 * 功能:增加字典信息时,自动生成最小的ID号码
 * 参数:String 字典表名称 first 字典ID的首字母,代表唯一的字典
 * 返回:String 生成的最小ID号码
 */
public String getId(String table, String first) {

// 所有除去首字母后的ID号码--整型,例如:11
int[] sid;
// 所有原始ID号码,例如:A011
String[] rid;
// 除去首字母后最小的ID号码--字符串
String sid_new = null;
// 程序返回的最小的原始ID号码
String rid_new = null;

        // 循环参数
int i = 0;
int k = 0;

con = DatabaseConnection.getConnection("jdbc/wutie";
Statement stm = null;
ResultSet rst = null;
RowSet rowRst = null;
String sql = "SELECT * FROM " + table + " order by id";

try {
    if (con.isClosed()) {
        throw new IllegalStateException("error.sql.unexpected";
    }
    stm = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
    rst = stm.executeQuery(sql);
    
    while (rst.next()) {
     k++;
     }
    sid = new int[k];
    rid = new String[k];
    rst = stm.executeQuery(sql);
    // 如果不存在结果集,则直接在first字母后面加001,例如first="A",rid_new=A001
    if (!rst.first()) {
     rid_new = first.concat("001";
     return rid_new;
     }
            // 如果存在结果集,则将表中所有ID号存入数组中,并转换为整型数据
    else {
     /*
    while (rst.next()) {
        rid[i] = rst.getString("id";
        sid[i] = Integer.parseInt(rid[i].substring(1));
        i++;
        }
        */
     for (rst.previous(); rst.next(); i++) {
     rid[i] = rst.getString("id";
     sid[i] = Integer.parseInt(rid[i].substring(1));
     }
     // 如果第一条记录ID号不为fisrt+001,例如A003、A018、A109等,则返回新增数据的ID号为A001
     if (sid[0] != 1) {
     rid_new = first.concat("001";
     return rid_new;
     }
     // 如果第一条记录ID号为first+001,即A001,则执行下面语句
    else {
     // 如果总记录数只有一条,例如A001,则返回新增数据为A002
     if (i == 1) {
     rid_new = first.concat("002";
     return rid_new;
     }
     else {
    for (int j = 1; j < k; j++) {
     // 如果相邻两条记录ID号的整数位相差1,则保存新增数据ID号整数位是前一位ID号整数位加1
     if (sid[j] == sid[j-1] + 1) {
     if (sid[j] < 9) {
       sid_new = String.valueOf(sid[j] + 1);
       rid_new = first.concat("00".concat(sid_new);
     }
       else if (sid[j]>9 && sid[j]<100){
       sid_new = String.valueOf(sid[j] + 1);
       rid_new = first.concat("0").concat(sid_new);
     }
     else {
       sid_new = String.valueOf(sid[j] + 1);
       rid_new = first.concat(sid_new);
     }
     }
// 如果相邻两条记录ID号的整数位相差非1,则返回新增数据ID号整数位是前一位ID号整数位加1
if (sid[j] != sid[j-1] + 1) {
if (sid[j-1] < 9) {
    sid_new = String.valueOf(sid[j-1] + 1);
    rid_new = first.concat("00".concat(sid_new);
    return rid_new;
}
else if (sid[j]>9 && sid[j]<100){
    sid_new = String.valueOf(sid[j-1] + 1);
    rid_new = first.concat("0").concat(sid_new);
}
else {
    sid_new = String.valueOf(sid[j-1] + 1);
    rid_new = first.concat(sid_new);
    return rid_new;
}
    }
}
    return rid_new;
     }
     }
     }     
}
catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("error.sql.runtime";
}
finally {
try {
stm.close();
con.close();
}
catch (SQLException e1) {
e1.printStackTrace();
throw new RuntimeException("error.sql.runtime";
}
}

}

注意:之所以生成A01而不是A1,是因为在SQLServer2000中根据ID号正确排序的需要,如果按照升序排列,A1后面是A10、A11等,而不是A2。另外,在Hibernate中有多种自动生成ID字段的方法,但是这个项目比较小,我没有使用Hibernate中间件,这里提供的只是生成字典ID字段的一种简单思路,相比原有算法改进了一点,可以适用于字典项不多于1000项的情况,一般情况下,字典项是不可能超过1000项了,在我参与的这个小项目中已经是完全够用了。还有什么更好的方法和思路还请大家多指教!

posted @ 2005-11-06 17:04 Flyingis 阅读(2131) | 评论 (0)编辑 收藏

内部类的作用

    作者:Flyingis

    内部类的功能在于,每个内部类都能独立的继承一个接口的实现,所以无论外围类是否已经继承了某个
(接口的)实现,对于内部类都没有影响。内部类使得多重继承的解决方案变得完整,并且内部类允许继承多个非接口类型(类或抽象类)

interface Sa {

  void today();

  void yesterday();

  boolean check();

}

public class Sab {

  private i = 10;

  private Sab_inner implements Sa {

void today() {

  return i;

}

void yesterday() {

  return --i;

}

Boolean check() {

  return i = = 0;

}

}

public Sa getSa() {

    return new Sab_inner();

}

}

         从上面这段代码可以看出,如果我们只是声明外围类Sab实现接口Sa,那么对于某个特定的Sab对象只能有一个Sa。但是如果使用了内部类,我们就可以通过方法getSa()来获得一个实现Sa接口的序列,这样就增加了应用上的灵活性。

         在控制框架,特别是图形用户界面的设计中更能体现内部类的价值,具体的可以参考这方面的资料。

posted @ 2005-11-05 12:11 Flyingis 阅读(781) | 评论 (0)编辑 收藏

理解Java内部类的基本特性(二)

作者:Flyingis

4. 
内部类拥有其外围类的所有元素的访问权,当某个外围类的对象创建了一个内部类对象时,此内部类对象必定会保存一个指向那个外围类对象的引用。然后,在访问此外围类的成员时,就是用那个“隐藏”的引用来选择外围类的成员。这与C++嵌套类的设计非常不同,在C++中只是单纯的名字隐藏机制,与外围对象没有联系,也没有隐含的访问权。

         另外,一个内部类被嵌套多少层并不重要,它能透明访问所有它所嵌入的外围类的所有成员。

5.  Java中实现C++的嵌套类功能也是通过嵌套类的机制来实现的,区别是C++中的嵌套类不能访问私有成员,在Java中则可以。

         Java中,使用嵌套类可以使得内部类对象与其外围类对象之间有联系,语法上是将内部类声明为static。而在普通的内部类中是不能有static数据、static字段和嵌套类的。通常,我们可以在一个普通的内部类中,通过一个特殊的this引用链接到其外围类对象,如外围类是Fruit,那么在内部类中应该通过Fruit.this来引用外围类的对象。

6.  内部类的继承比较特殊,我通过一个例子来向大家展示:

class Fruit {

  class Inner {}

}

public class Apple extends Fruit.Inner {

  Apple(Fruit f) {

    f.super(); //为什么要这样使用我也不明白

}

public static void main(String[] args) {

  Fruit f = new Fruit();

  Apple a = new Apple(f);

}

}

         其中为什么要外围类调用super()方法我也不清楚,希望有人指点!

7.  当继承某个外围类的时候,内部类并没有发生任何改变,基类和继承类中的两个内部类是完全独立的实体,各自在自己的命名空间内。如果明确继承某个内部类,则会覆盖原来的内部类。如:

public class A extends Atop {

  public Inner extends Atop.Inner {}

}

8.  局部内部类和匿名内部类在功能上基本相似,它们的区别在于,如果我们需要一个已命名的构造器,或者需要重载构造器,就要使用局部内部类,它可以提供多个内部类对象。匿名内部类只能用于实例初始化。

9.  内部类标识符是外围类的名字+$+内部类的名字,如果内部类是匿名的,则会由编译器产生一个数字作为其标识符。

posted @ 2005-11-04 18:55 Flyingis 阅读(1962) | 评论 (4)编辑 收藏

理解Java内部类的基本特性(一)

    作者:Flyingis

    内部类是
Java语言一个重要的基本特性,在Java开发的许多领域都会经常用到。内部类的定义说简单一点就是将一个类定义在另外一个类的内部。内部类允许你把一些逻辑相关的类组织在一起,控制内部类代码的可视性,它和类的组合是完全不同的概念。内部类主要有以下比较关键的特性:

 

1.  普通的非内部类不能被声明为privateprotected,否则就失去了创建该类的意义。但是内部类通常可以被声明为privateprotected类型,因为这样可以防止他人对该内部类实现的功能进行修改,达到隐藏实现细节的目的。例如:

class Fruit {

  private class Weight {

private String i;

private Weight(String j) {

  i = j;

}

public String read() {

  return i;

}

}

}

class test {

  public static void main(String[] args) {

Fruit f = new Fruit();

f.Weight w = f.new Weight(); //不能访问private类,如果Weightprotected类型则可以

}

}

2.  在方法或某控制语句(if/for/while)的作用域内定义内部类,将只能在该范围内调用内部类的方法和成员变量。

3.  匿名内部类是一种特殊的内部类,如果希望它使用一个在其外部定义的对象,那么编译器会要求其参数引用是final的。

public class Fruit {

  public Tea cont(final int j) {

return new Tea() {

  private int i = j;

  public int read() {

    return i;

}

}; //注意这里的分号

}

public static void main(String[] args) {

  Fruit f = new Fruit();

  Tea t = f.cont;

}

}

而当方法cont(final int j)中的参数j只是被传递到匿名类中的构造器时,可以不用被声明为final类型,如return new Tea(j)。这里提到了匿名内部类的构造器,那么它是怎么被初始化的呢?

public class Fruit {

  public Tea cont(int j) {

return new Tea(j) {

System.out.println(j);

};

}

}

         还可以这样初始化匿名内部类:

public class Fruit {

  public Tea cont(final int j) {

return new Tea(j) {

  int i;

  // 初始化匿名内部类

  {

  i = j;

  System.out.print(i);

}

};

}

}

         方法cont()可以被称为实例初始化方法,使得匿名内部类通过构造器而被初始化,在实际应用中,我们不能重载实例初始化方法,因为匿名内部类只能有一个构造方法。

posted @ 2005-11-04 17:11 Flyingis 阅读(1488) | 评论 (1)编辑 收藏

Java接口特性学习

作者:Flyingis

    在
Java中看到接口,第一个想到的可能就是C++中的多重继承和Java中的另外一个关键字abstract。从另外一个角度实现多重继承是接口的功能之一,接口的存在可以使Java中的对象可以向上转型为多个基类型,并且和抽象类一样可以防止他人创建该类的对象,因为接口不允许创建对象。

 

interface关键字用来声明一个接口,它可以产生一个完全抽象的类,并且不提供任何具体实现。interface的特性整理如下:

1.        接口中的方法可以有参数列表和返回类型,但不能有任何方法体。

2.        接口中可以包含字段,但是会被隐式的声明为staticfinal

3.        接口中的字段只是被存储在该接口的静态存储区域内,而不属于该接口。

4.        接口中的方法可以被声明为public或不声明,但结果都会按照public类型处理。

5.        当实现一个接口时,需要将被定义的方法声明为public类型的,否则为默认访问类型,Java编译器不允许这种情况。

6.        如果没有实现接口中所有方法,那么创建的仍然是一个接口。

7.        扩展一个接口来生成新的接口应使用关键字extends,实现一个接口使用implements

 

interface在某些地方和abstract有相似的地方,但是采用哪种方式来声明类主要参照以下两点:

1.        如果要创建不带任何方法定义和成员变量的基类,那么就应该选择接口而不是抽象类。

2.        如果知道某个类应该是基类,那么第一个选择的应该是让它成为一个接口,只有在必须要有方法定义和成员变量的时候,才应该选择抽象类。因为抽象类中允许存在一个或多个被具体实现的方法,只要方法没有被全部实现该类就仍是抽象类。

 

以上就是接口的基本特性和应用的领域,但是接口绝不仅仅如此,在Java语法结构中,接口可以被嵌套,既可以被某个类嵌套,也可以被接口嵌套。这在实际开发中可能应用的不多,但也是它的特性之一。需要注意的是,在实现某个接口时,并不需要实现嵌套在其内部的任何接口,而且,private接口不能在定义它的类之外被实现。

 

posted @ 2005-11-02 21:18 Flyingis 阅读(5072) | 评论 (0)编辑 收藏

多态学习心得

作者:Flyingis

    这几天我在重新复习
Java语言基础,虽然和团队一起,自己个人都进行了实际项目的开发,但越往上面走越觉得自己应该花点时间看看Java的基础知识,巩固一下基础。今天复习的是多态,同时写下自己的学习心得。

数据抽象、继承和多态是面向对象程序设计语言的三大特性。多态,我觉得它的作用就是用来将接口和实现分离开,改善代码的组织结构,增强代码的可读性。在某些很简单的情况下,或许我们不使用多态也能开发出满足我们需要的程序,但大多数情况,如果没有多态,就会觉得代码极其难以维护。

Java中,谈论多态就是在讨论方法调用的绑定,绑定就是将一个方法调用同一个方法主体关联起来。在C语言中,方法(C中称为函数)的绑定是由编译器来实现的,在英文中称为early binding(前期绑定),因此,大家自然就会想到相对应的late binding(后期绑定),这在Java中通常叫做run-time binding(运行时绑定),我个人觉得这样称呼更贴切,运行时绑定的目的就是在代码运行的时候能够判断对象的类型。通过一个简单的例子说明:

/**

 * 定义一个基类

 */

public Class Parents {

  public void print() {

    System.out.println(“parents”);

}

}

/**

 * 定义两个派生类

 */

public Class Father extends Parents {

  public void print() {

    System.out.println(“father”);

}

}

public Class Mother extends Parents {

  public void print() {

    System.out.println(“mother”);

}

}

/**

 * 测试输出结果的类

 */

public Class Test {

  public void find(Parents p) {

    p.print();

}

public static void main(String[] args) {

  Test t = new Test();

  Father f = new Father();

  Mother m = new Mother();

  t.find(f);

  t.find(m);

}

}

最后的输出结果分别是fathermother,将派生类的引用传给基类的引用,然后调用重写方法,基类的引用之所以能够找到应该调用那个派生类的方法,就是因为程序在运行时进行了绑定。

学过Java基础的人都能很容易理解上面的代码和多态的原理,但是仍有一些关键的地方需要注意的,算是自己对多态的一个小结:

1.        Java中除了staticfinal方法外,其他所有的方法都是运行时绑定的。在我另外一篇文章中说到private方法都被隐式指定为final的,因此final的方法不会在运行时绑定。当在派生类中重写基类中staticfinal、或private方法时,实质上是创建了一个新的方法。

2.        在派生类中,对于基类中的private方法,最好采用不同的名字。

3.        包含抽象方法的类叫做抽象类。注意定义里面包含这样的意思,只要类中包含一个抽象方法,该类就是抽象类。抽象类在派生中就是作为基类的角色,为不同的子类提供通用的接口。

4.        对象清理的顺序和创建的顺序相反,当然前提是自己想手动清理对象,因为大家都知道Java垃圾回收器。

5.        在基类的构造方法中小心调用基类中被重写的方法,这里涉及到对象初始化顺序。

6.        构造方法是被隐式声明为static方法。

7.        用继承表达行为间的差异,用字段表达状态上的变化。

posted @ 2005-10-31 19:28 Flyingis 阅读(1180) | 评论 (1)编辑 收藏

用Java实现自动在数据库表中生成ID号[原创]

    作者:Flyingis

    前段时间用Struts开发了一个B/S结构的信息管理系统,其中有一个功能是要求管理员能够对数据字典进行修改,数据字典的表结构基本上都是table(id, name),id为数据库其它表中所存储的内容,表示方式为A01、A02、A08、B10、B25、C12等等,一个字典就分配一个字母作为其ID号的标识,其实就是为了调试时方便,在其它的表中判断该字典的名称。因此对于一个特定的字典表来说,其ID号排序应该是A01、A02、A03、A04…… 

    在对字典内容进行删除的时候并不需要考虑什么,直接使用DELETE语句就可以了。关键是添加字典信息时,管理员需要在表单中填写的是table中的name字段,ID号如何生成就需要自己用代码来实现(包括ID号的01号空缺,中间有断开等情况)。下面是我设计的代码,其中关键的地方都有详细的注释:

/* 
 * 功能:增加字典信息时,自动生成最小的ID号码
 * 参数:String 字典表名称 first 字典ID的首字母,代表唯一的字典
 * 返回:String 生成的最小ID号码
 */
public String getId(String table, String first) {

// 所有除去首字母后的ID号码--整型,例如:11
int[] sid;
// 所有原始ID号码,例如:A11
String[] rid;
// 除去首字母后最小的ID号码--字符串
String sid_new = null;
// 程序返回的最小的原始ID号码
String rid_new = null;

        // 循环参数
int i = 0;
int k = 0;

con = DatabaseConnection.getConnection("jdbc/wutie");
Statement stm = null;
ResultSet rst = null;
RowSet rowRst = null;
String sql = "SELECT * FROM " + table + " order by id";

try {
    if (con.isClosed()) {
        throw new IllegalStateException("error.sql.unexpected");
    }
    stm = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
    rst = stm.executeQuery(sql);
    
    while (rst.next()) {
     k++;
     }
    sid = new int[k];
    rid = new String[k];
    rst = stm.executeQuery(sql);
    // 如果不存在结果集,则直接在first字母后面加01,例如first="A",rid_new=A01
    if (!rst.first()) {
     rid_new = first.concat("01");
     return rid_new;
     }
            // 如果存在结果集,则将表中所有ID号存入数组中,并转换为整型数据
    else {
     /*
    while (rst.next()) {
        rid[i] = rst.getString("id");
        sid[i] = Integer.parseInt(rid[i].substring(1));
        i++;
        }
        */
     for (rst.previous(); rst.next(); i++) {
     rid[i] = rst.getString("id");
     sid[i] = Integer.parseInt(rid[i].substring(1));
     }
     // 如果第一条记录ID号不为fisrt+01,例如A03、A05、A18等,则返回新增数据的ID号为A01
     if (sid[0] != 1) {
     rid_new = first.concat("01");
     return rid_new;
     }
     // 如果第一条记录ID号为first+1,即A1,则执行下面语句
    else {
     // 如果总记录数只有一条,例如A1,则返回新增数据为A02
     if (i == 1) {
     rid_new = first.concat("02");
     return rid_new;
     }
     else {
    for (int j = 1; j < k; j++) {
     // 如果相邻两条记录ID号的整数位相差1,则保存新增数据ID号整数位是前一位ID号整数位加1
     if (sid[j] == sid[j-1] + 1) {
     if (sid[j] < 9) {
     sid_new = String.valueOf(sid[j] + 1);
    rid_new = first.concat("0").concat(sid_new);
     }
     else {
     sid_new = String.valueOf(sid[j] + 1);
    rid_new = first.concat(sid_new);
     }
     }
// 如果相邻两条记录ID号的整数位相差非1,则返回新增数据ID号整数位是前一位ID号整数位加1
if (sid[j] != sid[j-1] + 1) {
if (sid[j-1] < 9) {
    sid_new = String.valueOf(sid[j-1] + 1);
    rid_new = first.concat("0").concat(sid_new);
    return rid_new;
}
else {
    sid_new = String.valueOf(sid[j-1] + 1);
    rid_new = first.concat(sid_new);
    return rid_new;
}
    }
}
    return rid_new;
     }
     }
     }     
}
catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("error.sql.runtime");
}
finally {
try {
stm.close();
con.close();
}
catch (SQLException e1) {
e1.printStackTrace();
throw new RuntimeException("error.sql.runtime");
}
}

}
    
    注意:之所以生成A01而不是A1,是因为在SQLServer2000中根据ID号正确排序的需要,如果按照升序排列,A1后面是A10、A11等,而不是A2。另外,在Hibernate中有多种自动生成ID字段的方法,但是这个项目比较小,我没有使用Hibernate中间件,这里提供的只是生成字典ID字段的一种简单思路,只能用于字典项不多于100项的情况,一般的情况可以满足了,但如果超过100项只需简单修改一下代码,不足之处还请大家多指教!

posted @ 2005-10-31 11:37 Flyingis 阅读(1073) | 评论 (1)编辑 收藏