??xml version="1.0" encoding="utf-8" standalone="yes"?>欧美精品久久久久久久,77777少妇光屁股久久一区,大伊人狠狠躁夜夜躁av一区http://www.aygfsteel.com/mlw2000/category/13102.htmlBe happy here...zh-cnSun, 20 May 2007 19:14:19 GMTSun, 20 May 2007 19:14:19 GMT60抽象cM接口的区?转蝲)http://www.aygfsteel.com/mlw2000/articles/117769.htmlmlw2000mlw2000Wed, 16 May 2007 01:42:00 GMThttp://www.aygfsteel.com/mlw2000/articles/117769.htmlhttp://www.aygfsteel.com/mlw2000/comments/117769.htmlhttp://www.aygfsteel.com/mlw2000/articles/117769.html#Feedback0http://www.aygfsteel.com/mlw2000/comments/commentRss/117769.htmlhttp://www.aygfsteel.com/mlw2000/services/trackbacks/117769.htmlabstract class?font color=#000000>interface是Java语言中对于抽象类定义q行支持的两U机Ӟ正是׃q两U机制的存在Q才赋予了Java强大的面向对象能力?nbsp;abstract class和interface之间在对于抽象类定义的支持方面具有很大的怼性,甚至可以怺替换Q因此很多开发者在q行抽象cd义时对于 abstract class和interface的选择昑־比较随意?br>其实Q两者之间还是有很大的区别的Q对于它们的选择甚至反映出对于问题领域本质的理解、对于设计意囄理解是否正确、合理。本文将对它们之间的区别q行一番剖析,试图l开发者提供一个在二者之间进行选择的依据?br>一、理解抽象类
abstract class和interface在Java语言中都是用来进行抽象类Q本文中的抽象类q从abstract class译而来Q它表示的是一个抽象体Q而abstract class为Java语言中用于定义抽象类的一U方法,误者注意区分)定义的,那么什么是抽象c,使用抽象c能为我们带来什么好处呢Q?br>在面向对象的概念中,我们知道所有的对象都是通过cL描绘的,但是反过来却不是q样。ƈ不是所有的c都是用来描l对象的Q如果一个类中没有包含够的信息来描l一个具体的对象Q这Lcd是抽象类。抽象类往往用来表征我们在对问题领域q行分析、设计中得出的抽象概念,是对一pd看上M同,但是本质上相同的具体概念的抽象?br>比如Q如果我们进行一个图形编辑Y件的开发,׃发现问题领域存在着圆、三角Şq样一些具体概念,它们是不同的Q但是它们又都属于Ş状这样一个概念,形状q个概念在问题领域是不存在的Q它是一个抽象概c正是因为抽象的概念在问题领域没有对应的具体概念Q所以用以表征抽象概늚抽象cL不能够实例化的?br>在面向对象领域,抽象cM要用来进行类型隐藏。我们可以构造出一个固定的一l行为的抽象描述Q但是这l行为却能够有Q意个可能的具体实现方式。这个抽象描q就是抽象类Q而这一lQ意个可能的具体实现则表现为所有可能的zcR模块可以操作一个抽象体。由于模块依赖于一个固定的抽象体,因此它可以是不允怿改的Q同Ӟ通过从这个抽象体zQ也可扩展此模块的行为功能。熟悉OCP的读者一定知道,Z能够实现面向对象设计的一个最核心的原则OCP(Open-Closed Principle)Q抽象类是其中的关键所在?br>二、从语法定义层面看abstract class和interface
在语法层面,Java语言对于abstract class和interfacel出了不同的定义方式Q下面以定义一个名为Demo的抽象类Z来说明这U不同。用abstract class的方式定义Demo抽象cȝ方式如下Q?br>
abstract class Demo ?br>abstract void method1();
abstract void method2();

?br>

使用interface的方式定义Demo抽象cȝ方式如下Q?br>
interface Demo {
void method1();
void method2();

}


在abstract class方式中,Demo可以有自q数据成员Q也可以有非abstarct的成员方法,而在interface方式的实CQDemo只能够有静态的不能被修改的数据成员Q也是必须是static final的,不过在interface中一般不定义数据成员Q,所有的成员Ҏ都是abstract的。从某种意义上说Qinterface是一U特DŞ式的abstract class?br>从编E的角度来看Qabstract class和interface都可以用来实?design by contract"的思想。但是在具体的用上面还是有一些区别的?br>首先Qabstract class在Java语言中表C的是一U承关p,一个类只能使用一ơ承关pR但是,一个类却可以实现多个interface。也许,q是Java语言的设计者在考虑Java对于多重l承的支持方面的一U折中考虑吧?br>其次Q在abstract class的定义中Q我们可以赋予方法的默认行ؓ。但是在interface的定义中Q方法却不能拥有默认行ؓQؓ了绕q这个限Ӟ必须使用委托Q但是这?nbsp;增加一些复杂性,有时会造成很大的麻烦?br>在抽象类中不能定义默认行存在另一个比较严重的问题Q那是可能会造成l护上的ȝ。因为如果后来想修改cȝ界面Q一般通过abstract class或者interface来表C)以适应新的情况Q比如,d新的Ҏ或者给已用的方法中d新的参数Q时Q就会非常的ȝQ可能要p很多的时_对于zcd多的情况Q尤为如此)。但是如果界面是通过abstract class来实现的Q那么可能就只需要修改定义在abstract class中的默认行ؓ可以了?br>同样Q如果不能在抽象cM定义默认行ؓQ就会导致同LҎ实现出现在该抽象cȝ每一个派生类中,q反?nbsp;"one ruleQone place"原则Q造成代码重复Q同样不利于以后的维护。因此,在abstract class和interface间进行选择时要非常的小心?br>三、从设计理念层面看abstract class和interface
上面主要从语法定义和~程的角度论qCabstract class和interface的区别,q些层面的区别是比较低层ơ的、非本质的。本文将从另一个层面:abstract class和interface所反映出的设计理念Q来分析一下二者的区别。作者认为,从这个层面进行分析才能理解二者概늚本质所在?br>前面已经提到q,abstarct class在Java语言中体C一U承关p,要想使得l承关系合理Q父cdzcM间必d?is a"关系Q即父类和派生类在概忉|质上应该是相同的。对于interface 来说则不Ӟq不要求interface的实现者和interface定义在概忉|质上是一致的Q仅仅是实现了interface定义的契U而已。ؓ了便于理解Q下面将通过一个简单的实例q行说明?br>考虑q样一个例子,假设在我们的问题领域中有一个关于Door的抽象概念,该Doorh执行两个动作open和closeQ此时我们可以通过abstract class或者interface来定义一个表C抽象概念的类型,定义方式分别如下所C:

使用abstract class方式定义DoorQ?br>
abstract class Door {
abstract void open();
abstract void close()Q?br>}

使用interface方式定义DoorQ?br>
interface Door {
void open();
void close();
}


其他具体的Doorcd可以extends使用abstract class方式定义的Door或者implements使用interface方式定义的Door。看h好像使用abstract class和interface没有大的区别?br>如果现在要求Doorq要h报警的功能。我们该如何设计针对该例子的cȝ构呢Q在本例中,主要是ؓ了展Cabstract class和interface反映在设计理念上的区别,其他斚w无关的问题都做了化或者忽略)下面罗列出可能的解x案,q从设计理念层面对这些不同的Ҏq行分析?br>解决Ҏ一Q?br>单的在Door的定义中增加一个alarmҎQ如下:

abstract class Door {
abstract void open();
abstract void close()Q?br>abstract void alarm();
}


或?br>
interface Door {
void open();
void close();
void alarm();
}


那么h报警功能的AlarmDoor的定义方式如下:

class AlarmDoor extends Door {
void open() { … }
void close() { … }
void alarm() { … }
}


或?br>
class AlarmDoor implements Door ?br>void open() { … }
void close() { … }
void alarm() { … }
?br>

q种Ҏq反了面向对象设计中的一个核心原则ISPQInterface Segregation PricipleQ,在Door的定义中把Door概念本n固有的行为方法和另外一个概?报警?的行为方法؜在了一赗这样引L一个问题是那些仅仅依赖于Doorq个概念的模块会因ؓ"报警?q个概念的改变(比如Q修改alarmҎ的参敎ͼ而改变,反之依然?br>解决Ҏ二:
既然open、close和alarm属于两个不同的概念,ҎISP原则应该把它们分别定义在代表q两个概늚抽象cM。定义方式有Q这两个概念都?nbsp;abstract class方式定义Q两个概念都使用interface方式定义Q一个概念用abstract class方式定义Q另一个概念用interface方式定义?br>昄Q由于Java语言不支持多重承,所以两个概念都使用abstract class方式定义是不可行的。后面两U方式都是可行的Q但是对于它们的选择却反映出对于问题领域中的概念本质的理解、对于设计意囄反映是否正确、合理。我们一一来分析、说明?br>如果两个概念都用interface方式来定义,那么反映出两个问题Q?br>1、我们可能没有理解清楚问题领域,AlarmDoor在概忉|质上到底是Doorq是报警器?
2、如果我们对于问题领域的理解没有问题Q比如:我们通过对于问题领域的分析发现AlarmDoor在概忉|质上和Door是一致的Q那么我们在实现时就没有能够正确的揭C我们的设计意图Q因为在q两个概늚定义上(均用interface方式定义Q反映不Zq含义?br>如果我们对于问题领域的理解是QAlarmDoor在概忉|质上是DoorQ同时它有具有报警的功能。我们该如何来设计、实现来明确的反映出我们的意思呢Q前面已l说q, abstract class在Java语言中表CZU承关p,而承关pd本质上是"is a"关系。所以对于Doorq个概念Q我们应该用abstarct class方式来定义。另外,AlarmDoor又具有报警功能,说明它又能够完成报警概念中定义的行ؓQ所以报警概念可以通过interface方式定义。如下所C:

abstract class Door {
abstract void open();
abstract void close()Q?br>}
interface Alarm {
void alarm();
}
class AlarmDoor extends Door implements Alarm {
void open() { … }
void close() { … }
void alarm() { … }
}


q种实现方式基本上能够明的反映出我们对于问题领域的理解Q正的揭示我们的设计意图。其实abstract class表示的是"is a"关系Qinterface表示的是"like a"关系Q大家在选择时可以作Z个依据,当然q是建立在对问题领域的理解上的,比如Q如果我们认为AlarmDoor在概忉|质上是报警器Q同时又h Door的功能,那么上述的定义方式就要反q来了?br>abstract class和interface是Java语言中的两种定义抽象cȝ方式Q它们之间有很大的相似性。但是对于它们的选择却又往往反映出对于问题领域中的概忉|质的理解、对于设计意囄反映是否正确、合理,因ؓ它们表现了概念间的不同的关系Q虽焉能够实现需求的功能Q。这其实也是语言的一U的惯用法,希望读者朋友能够细l体?

mlw2000 2007-05-16 09:42 发表评论
]]>
Hibernate的性能(转脓)http://www.aygfsteel.com/mlw2000/articles/105711.htmlmlw2000mlw2000Fri, 23 Mar 2007 01:31:00 GMThttp://www.aygfsteel.com/mlw2000/articles/105711.htmlhttp://www.aygfsteel.com/mlw2000/comments/105711.htmlhttp://www.aygfsteel.com/mlw2000/articles/105711.html#Feedback0http://www.aygfsteel.com/mlw2000/comments/commentRss/105711.htmlhttp://www.aygfsteel.com/mlw2000/services/trackbacks/105711.htmlHibernate的性能(转脓)

xieccQ?br />我们的项目从d12月䆾启动Q采用了Struts+Hibernate的架构,一开始用Hibernate的时候速度极快Q对象操作异常方便,大家都说爽歪歪?
可惜好景不长Q随着我们对象关系的不断复杂,数据量的不断增加QHibernate的性能急剧下降。具体表CؓQ我们在设计对象旉用了很多的one-to-many和many-to-one的关p,在取某个对象的几个简单的属性时Q它会把所有关联的子对象都取出来,l常出在取一个简单属性的时候,调试H口的SQL语句一屏一屏地往下闪。到最后我的一个test跑完需要1Q分钟?
在忍无可忍之下,我们开始性能优化ҎQ以下我们优化所做的一些事情:
1、将所以one-to-many的关p里lazy设成true
2、修改hibernate.propertiesQ增加了以下两句Q?
hibernate.jdbc.fetch_size=50
hibernate.jdbc.batch_size=100
3、调整WebLogic的pool
4、利用Hibernate提供的CGLIB Proxy机制Qmany-to-one关系的子对象也可以lazy initialization
Q但是我发现调试H口里仍会有取子对象的SQL语句Q但速度实快了Q?
5、利用Hibernate提供的Cache机制Q对关键对象使用Cache
l果优化以后Q我的test可以从原来的12分钟变成50U钟跑完?
原以Z事大吉了Q但当我们面对客L时候,才发现我们系l的性能q远q不够?
我们现在pȝ试运行约两个月,l常在数据保存或者查询时{上一分钟甚至两分钟?
׃客户原来的系l用asp+SQL Server写的Q速度很快。二者一ҎQ我们就被客户骂得惨不忍睏V?
优化真是一件很烦h的事Q在不改动系l框架的情况下,不知q有哪些提高pȝ性能的方法?

freecodeQ?br />同感Q虽然我不用Q不懂hibernate.
前段旉Q我们做了个目Q对一些取数的q程Q采用了javascript脚本Q再通过bsf~译Q运行时Q时间巨长,人家说以前用foxpro做的Q快多了Q弄得我们很没面子?/p>

dhj1Q?br />我也?Struts+Hibernate 做大型项?在ƈ发很高时,每天4500人次讉K量的情况?性能也相当不?

做的旉有几点考虑:

1.大东?如果很多很多的one-to-many和many-to-one的关p? 必定会媄响性能,我刚学习Hibernate 时就有这U直?所以我们没有用one-to-many和many-to-one的关p?而是象SQL一LL作表的关pL识符.

2.如果大的系l?最l必ȝ成HTML的文?是有数据库中有数据更新?自动生成一个HTML文g.大多数用h在只ȝ?在只ȝ态下只LCHTML文g,节省很多资源.

3.更用CHACHE表技?把访问量高的记录自动提到CACHE表中.

xieccQ?br />谢谢dhj1l我提的?
在hibernate|站上看到的好多资源几乎都说hibernate的性能不错Q而且很多人开发的pȝ性能也不错,包括dhj1的,看来hibernate无罪Q是我们设计得太滥了?
不过q是有点疑问?
1、dhj1提到的第一点很有道理。我们确实在有些关键的地方用了标识符来关联。但是我们这个系l的兌实现太多了,如果所以有东西都用标识W作兌的话Q那我们的实体层设计退化成为面向关pȝER图设计,那我们要Hibernate何用Q我用感觉用Hibernate时最大的便利不是在写代码的时候用对象的操作代替SQL语句,而是在徏模的时候可以用面向对象的思维把很复杂的逻辑用UML图表C出?然后直接转化成实体。所以我们在性能影响太大的地斚w用了面向对象和关pȝl合的方式,但在更多的地方仍然只能采用对象关联的方式?
Q、生成静态ᅢQ_݋Q,对特定的pȝ实有用Q但我们pȝ中的数据几乎都是动态的Q所以实现v来有困难。而且我也不太清楚q样做的隑ֺ有多高,具体怎么实现Q请dhj1指点qh|?
Q、Cache我们已经采用了。但proxy的用法我至今仍然有点qL?
在Hibernate的文档里g只要在定义文仉加这么一句就可以了:
 <class name="eg.Order" proxy="eg.Order">
但实际用时我们发现q样做之后,Hibernate取数据时的SQL语句g一句都没有?
我们现在的想法是自已来实现Proxyc,它的接口与实体完全一P在Proxy里SQL语句来实现取数据操作。不知是否可行?

sanwaQ?br />我在设计pȝ?Ҏ个对象图都会采用两套映射模型,
一套用于映实际的UML,当然包括引用,q套对象图主要用于根据关联对象的属性来查询对象时?很少用于更新数据,除非是聚集类.
另一套映?把对象引用映ؓLong型的属?传递到业务层或表示?需要相关的对象引用?再用q个引用来load对象.而且,对于需要load的对象可以用代理或直接多映一个简单类来处?
另外,对于大数据量的查询或表的兌层次较深(过三层),采用jdbc直接处理.

方世玉:
我们现在也正在用hibernateq行目开?
我认Z是所有相关的表都要做one ManyQmany one映射?
比如说一个用户和他的定购业务Q我们做了双向关联?
但是q个用户的话单就不能和用户做M兌了。话单表每天都有数十万条Q就是做manyone兌也非常吓人,宁可到时候用hql来查?/p>

xieccQ?br />呵呵,hsanwaQ这两套映射模型如何在一个应用中同时使用Q?/p>


dhj1Q?br />我用hibernate,是可以减开发工作量. 特别在开发中或维护过E中对表l构的改?用HIBERNATE是很方便?

做了DAO?对表的父子关pȝ的处?通过ID标识,也只是两三句E序语句.操作也很方便,而且更灵z?

生成静态ᅢQ_݋Q?以后我做q这Lpȝ,q在XXX省信息港|站上大量?性能当然不错,同时1400人在U?真正的在U?不是那种用网|个几分钟h一ơg时的那种在线),性能也不?开发当然会有一些难?

我说的CACHE不是说用HIBERNATE的CACHE.而是自已开发的,把访问量高的信息自动攑ֈ一个表中去,q个表保证只?00讉K量最高的条记?多于100条记录的出M.

sanwaQ?br />举个例子,比如用户的权?在我们的pȝ中涉及用PUserQ、权?Acl)、组?Component)、组件类(componentDomain){几个对象的兌?
W一套映图Q反映他们的实际关系Q即对应UML模型。User和Acl的关联映ؓidbagQ不要直接映ؓset,因ؓ在我设计的关联表中存在代理主键,代理主键在第二套映射图中实际为用h限的id.
W二套映图Q只映射用户QUserSOQ和用户拥有的权?UserAclSO)Q是one to many的关pR?
后缀SO表示相关cȝ单对象映类?

q样Q当客户端需要获取某个用L所有权限时Q直接用W二套映图。返回的集合中就只包括Acl的id。如果要获取用户Ҏ个组件域的权限,则用W一套映图Q用强大的HQL查询Q再转换为第二套映射图返回到客户端?
当更新用L权限Ӟ也用W二套映图Q直接操作UserSO和UserAclSOQ传回更新?

使用cM的设计策略时Q对many to many的关联表Q都采用代理主键Q而不是联合主键,q样Q两套映图都较Ҏ存取数据。只是,多数情况下用W二套映图?

当然,我的E序架构是Swing + Session Bean + DAO + Hibernate + DB,Swing和Session Bean的通信可以用HTTP或RMI,在我的架构中,lazy loading发挥不了多大的作用,才采取这U策略。如果在lazy loading可以发挥作用的地方,对大多数对象图,是没有必要采取这U策略的?

另外Q在我的架构中,swing层有一个组件是可以Ҏ一个ID来加载这个类的属性,直接用jdbc实现的,独立于Hibernate

xiaoyuQ?br />我也说上一句吧?

虽然HB是好Q方便,但有x据库设计的一些性能原则q是要考虑的?

毕竟它只是Mapping而已?
所以也要设|烦引等东西?/p>

jxb8901Q?br />上面的proxy和cache没有M关系Q只是用于lazy loadingQ请看hibernate中文文档W?章:

java代码: 

proxy (可?: 指定一个接口,在gq装载时作ؓ代理使用。你可以在这里用该c自q名字?

coolwycQ?br />Z在性能上得到^?对many-to-one不直接用关q?例如:user&ACL,取user?不取ACL,要取ACL先取user,再取ACL,毕竟应用取user的频率比取ACL?没必要在取user是硬要把ACL一起取出来.

q有其他many-to-one都和q个很类?如果many很少的话没问题,例如:?amp;宠物,通常一个h只有于{于一个宠?q种情况取h的时候把宠物一起取出对pȝ影响不大

willmacQ?br />hibernate本n的性能非常好,关键在设计本w?
和你的数据库本nQ以及你的访问量和数据库的性质
针对不同的环境一定要有不同的设计的,一套设计肯定不能适用于全部的环境
我D个典型例子来说吧
你的hibernate设计可以采用单session的方式,也可以采用多session的方式,应用环境不同Q结果也大大的不同。当用户人群,数据库记录两低的时候,多session的设计是非常有优势的Q这是Z么那么多?
反对使用threadlocal理session的主要理由把Q的?
把两U设计都攑֜q里Q你会发现多session的性效要比
threadlocal的强太多了,q且~程也异常的ҎQ这U例子,我不再D了,你在q个论坛上都可以下的到。可?
当h变多,数据库记录v量增长的时候,我们发现问题来了Q我们做的应用无限制的吃d存,应用的响应开始变慢,q是Z么呢Q不知道大家是否理解I竟什么是sessionQ其实从Ҏ上说是一张hashmap,q样大家好理解了,当不同的用户Q同时访问应用的时候,不同的h建立不同的连表,然后释放Q而当q发人群急速增长的时候,于是问题来了。那怎么办,threadlocal没有其他的办法,你要解决一个同步的问题Q我们只有一个session,你不能够同时往里读取数据,然后又写入数据的Qƈ发用戯么多Q你只可以让他们一个一个得来!Q!
哇,q样效率不是太低了,的确Q我一开始就说了Q小型系l,使用threadlocall对是低效的做法的,可是当规模上来了之后Q我们再来看Q内存不再无限制的开销Qcpu徯荷也降下来了Q唯一一点发生变化的是,用户的客L可能多等?.001U钟Q一个在服务D队列的旉Q这是设计?
讲了一个设计的例子Q我们来看多对一Q一对多Q会让我们应用的效率降低么?
h意hibernate只是帮助我们完成了mapping 的工?
原来的一对多也好或者多对一也好Q本来就存在的,之所以让你觉得效率低Q是因ؓ在得到父亲后Q还要去把每一个儿子给d来,可是注意Q你只是多执行了一条sql而已Qؓ什么会慢的呢,我想问题q是在设计之?


 



mlw2000 2007-03-23 09:31 发表评论
]]>
解析Javacd对象的初始化q程【{?/title><link>http://www.aygfsteel.com/mlw2000/articles/85162.html</link><dc:creator>mlw2000</dc:creator><author>mlw2000</author><pubDate>Sun, 03 Dec 2006 02:49:00 GMT</pubDate><guid>http://www.aygfsteel.com/mlw2000/articles/85162.html</guid><wfw:comment>http://www.aygfsteel.com/mlw2000/comments/85162.html</wfw:comment><comments>http://www.aygfsteel.com/mlw2000/articles/85162.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/mlw2000/comments/commentRss/85162.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/mlw2000/services/trackbacks/85162.html</trackback:ping><description><![CDATA[               出处Qblog 责Q~辑Q?方舟 <!-- #EndEditable --><table height="65" cellspacing="0" cellpadding="0" width="760" align="center" border="0"><tbody><tr><td class="content" height="65"><!-- #BeginEditable "3" --><table class="content" width="100%" align="center" border="0"><tbody><tr><td class="content"><p>cȝ初始化和对象初始化是 JVM 理的类型生命周期中非常重要的两个环节,Google 了一遍网l,有关c装载机制的文章倒是不少Q然而类初始化和对象初始化的文章q不多,特别是从字节码和 JVM 层次来分析的文章更是鲜有所见?/p><p>本文主要对类和对象初始化全过E进行分析,通过一个实际问题引入,源代码转换?JVM 字节码后Q对 JVM 执行q程的关键点q行全面解析Qƈ在文中穿插入了相?JVM 规范?JVM 的部分内部理论知识,以理Z实际l合的方式介l对象初始化和类初始化之间的协作以及可能存在的冲H问题?/p><p><strong>问题引入</strong></p><p>q日我在调试一个枚丄型的解析器程序,该解析器是将数据库内一万多条枚举代码装载到~存中,Z实现快速定位枚举代码和具体枚Dcd的所有枚丑օ素,该类在装载枚举代码的同时对其采取两种{略建立内存索引。由于该cL一个公共服务类Q在E序各个层面都会使用到它Q因此我它实现Z个单例类。这个类在我调整cd例化语句位置之前q行正常Q但当我把该cd例化语句调整到静态初始化语句之前Ӟ我的E序不再为我工作了?下面是经q我化后的示例代码:</p><p><strong>QL单一Q?/strong></p><table width="100%"><tbody><tr><td class="content" bgcolor="#cccccc">package com.ccb.framework.enums;<br />import java.util.Collections;<br />import java.util.HashMap;<br />import java.util.Map;<br />public class CachingEnumResolver { <br /> //单态实例 一切问题皆由此行引?<br /> private static final CachingEnumResolver SINGLE_ENUM_RESOLVER = new CachingEnumResolver(); <br /> /*MSGCODE->Category内存索引*/ <br /> private static Map CODE_MAP_CACHE; <br /> static {<br />  CODE_MAP_CACHE = new HashMap(); <br />  //Z说明问题,我在q里初始化一条数?<br />  CODE_MAP_CACHE.put("0","北京?); <br /> }<br /> //private, for single instance <br /> private CachingEnumResolver() {<br />  //初始化加载数?引v问题Q该Ҏ也要负点责Q <br />  initEnums();<br /> }<br /> /** * 初始化所有的枚Dcd */ <br /> public static void initEnums() { <br />  // ~~~~~~~~~问题从这里开始暴?~~~~~~~~~~~//<br />  if (null == CODE_MAP_CACHE) { <br />   System.out.println("CODE_MAP_CACHE为空,问题在这里开始暴?"); <br />   CODE_MAP_CACHE = new HashMap(); <br />  }<br />  CODE_MAP_CACHE.put("1", "北京?);<br />  CODE_MAP_CACHE.put("2", "云南?); <br />  //..... other code...<br /> }<br /> public Map getCache() {<br />  return Collections.unmodifiableMap(CODE_MAP_CACHE);<br /> }<br /> /** * 获取单态实?* * @return */<br /> public static CachingEnumResolver getInstance() { <br />  return SINGLE_ENUM_RESOLVER; <br /> }<br /> public static void main(String[] args) {<br />  System.out.println(CachingEnumResolver.getInstance().getCache());<br /> }<br />} </td></tr></tbody></table><p>惛_大家看了上面的代码后会感觉有些茫Ӟq个cȝh没有问题啊,q的属于典型的饿汉式单态模式啊Q怎么会有问题呢?</p><p>是的Q他看v来的没有问题,可是如果他 run hӞ其结果是他不会ؓ你正?work。运行该c,它的执行l果是:</p><p><strong>QL单二Q?/strong></p><table width="100%"><tbody><tr><td class="content" bgcolor="#cccccc">CODE_MAP_CACHE为空,问题在这里开始暴?{0=北京市}</td></tr></tbody></table><p>我的E序怎么会这PZ么在 initEnum() Ҏ?CODE_MAP_CACHE 为空Qؓ什么我输出?CODE_MAP_CACHE 内容只有一个元素,其它两个元素呢?Q?Q!Q?/p><p>看到q里Q如果是你在调试该程序,你此M定觉得很奇怪,N是我?Jvm 有问题吗Q非也!如果不是Q那我的E序是怎么了?q绝对不是我惌的结果。可事实上无论怎么修改 initEnum() Ҏ都无于事,L我最初是一定不会怀疑到问题可能出在创徏 CachingEnumResolver 实例q一环节上。正是因为我太相信我创徏 CachingEnumResolver 实例的方法,加之?Java cd始化与对象实例化底层原理理解有所偏差Q我ؓ此付Z三、四个小?-U半个工作日的大好青春?/p><p>那么问题I竟出在哪里呢?Z么会出现q样的怪事呢?在解册个问题之前,先让我们来了解一下JVM的类和对象初始化的底层机制?/p><p><strong>cȝ生命周期</strong><br /> <img height="243" src="http://www.uml.org.cn/j2ee/images/e892zpk371ap.jpg" width="511" /><br />  上图展示的是cȝ命周期流向;在本文里Q我只打谈谈类?初始?以及"对象实例?两个阶段?</p><p><strong>cd始化</strong></p><p>c?初始?阶段Q它是一个类或接口被首次使用的前阶段中的最后一工作,本阶D负责ؓcd量赋予正的初始倹{?/p><p>Java ~译器把所有的cd量初始化语句和类型的静态初始化器通通收集到 <clinit> Ҏ内,该方法只能被 Jvm 调用Q专门承担初始化工作?/p><p>除接口以外,初始化一个类之前必须保证其直接超cd被初始化Qƈ且该初始化过E是?Jvm 保证U程安全的。另外,q所有的c都会拥有一?<clinit>() ҎQ在以下条g中该cM会拥?<clinit>() ҎQ?/p><p>该类既没有声明Q何类变量Q也没有静态初始化语句Q该cd明了cd量,但没有明用类变量初始化语句或静态初始化语句初始化;该类仅包含静?final 变量的类变量初始化语句,q且cd量初始化语句是编译时帔R表达式?<br /><br /> <strong>对象初始?/strong></p><p>在类被装载、连接和初始化,q个cd随时都可能用了。对象实例化和初始化是就是对象生命的起始阶段的活动,在这里我们主要讨论对象的初始化工作的相关特点?/p><p>Java ~译器在~译每个cL都会c至生成一个实例初始化Ҏ--?"<init>()" Ҏ。此Ҏ与源代码中的每个构造方法相对应Q如果类没有明确地声明Q何构造方法,~译器则cȝ成一个默认的无参构造方法,q个默认的构造器仅仅调用父类的无参构造器Q与此同时也会生成一个与默认构造方法对应的 "<init>()" Ҏ.</p><p>通常来说Q?lt;init>() Ҏ内包括的代码内容大概为:调用另一?<init>() ҎQ对实例变量初始化;与其对应的构造方法内的代码?如果构造方法是明确C调用同一个类中的另一个构造方法开始,那它对应?<init>() Ҏ体内包括的内容ؓQ一个对本类?<init>() Ҏ的调用;对应用构造方法内的所有字节码?/p><p>如果构造方法不是通过调用自ncȝ其它构造方法开始,q且该对象不?Object 对象Q那 <init>() 法内则包括的内容为:一个对父类 <init>() Ҏ的调用;对实例变量初始化Ҏ的字节码Q最后是对应构造子的方法体字节码?/p><p>如果q个cL ObjectQ那么它?<init>() Ҏ则不包括对父c?<init>() Ҏ的调用?/p><p><strong>cȝ初始化时?/strong></p><p>本文到目前ؓ止,我们已经大概有了解到了类生命周期中都l历了哪些阶D,但这个类的生命周期的开始阶D?-c装载又是在什么时候被触发呢?cd是何时被初始化的呢?让我们带着q三个疑问l去L{案?/p><p>Java 虚拟范ؓcȝ初始化时机做了严格定义:"initialize on first active use"--" 在首ơ主动用时初始?。这个规则直接媄响着c装载、连接和初始化类的机?-因ؓ在类型被初始化之前它必须已经被连接,然而在q接之前又必M证它已经被装载了?/p><p>在与初始化时机相关的c装载时机问题上QJava 虚拟范ƈ没有对其做严格的定义Q这׃?JVM 在实C可以Ҏ自己的特Ҏ供采用不同的装蝲{略。我们可以思考一?Jboss AOP 框架的实现原理,它就是在对你?class 文g装蝲环节做了手脚--插入?AOP 的相x截字节码Q这使得它可以对E序员做到完全透明化,哪怕你?new 操作W创建出的对象实例也一栯?AOP 框架拦截--与之相对应的 Spring AOPQ你必须通过他的 BeanFactory 获得?AOP 代理q的受管对象Q当?Jboss AOP 的缺点也很明?-他是?JBOSS 服务器绑定很紧密的,你不能很L的移植到其它服务器上。嗯~……,说到q里有些跑题了,要知?AOP 实现{略_以写一本厚厚的书了Q嘿嘿,此打住?/p><p>说了q么多,cȝ初始化时机就是在"在首ơ主动用时"Q那么,哪些情Ş下才W合首次d使用的要求呢Q?/p><p>首次d使用的情形:</p><p>·创徏某个cȝ新实例时--new、反、克隆或反序列化Q?</p><p>·调用某个cȝ静态方法时Q?</p><p>·使用某个cL接口的静态字D|对该字段赋值时Qfinal字段除外Q; </p><p>·调用Java的某些反方法时 </p><p>·初始化某个类的子cL </p><p>·在虚拟机启动时某个含有main()Ҏ的那个启动类?</p><p>除了以上几种情Ş以外Q所有其它用JAVAcd的方式都是被动用的Q他们不会导致类的初始化?/p><p><strong>我的问题I竟出在哪里</strong></p><p>好了Q了解了JVM的类初始化与对象初始化机制后Q我们就有了理论基础Q也可以理性的d析问题了?/p><p>下面让我们来看看前面[清单一]的JAVA源代码反l译出的字节码:</p><p><strong>QL单三Q?/strong></p><table width="100%"><tbody><tr><td class="content" bgcolor="#cccccc">public class com.ccb.framework.enums.CachingEnumResolver extendsjava.lang.Object{<br /> static {};<br /> Code: 0: new #2; <br /> //class CachingEnumResolver<br /> 3: dup<br /> 4: invokespecial #14; <br /> //Method "<init>":()V ?<br /> 7: putstatic #16; <br /> //Field SINGLE_ENUM_RESOLVER:Lcom/ccb/framework/enums/CachingEnumResolver; <br /> 10: new #18;<br /> //class HashMap ?<br /> 13: dup <br /> 14: invokespecial #19;<br /> //Method java/util/HashMap."<init>":()V <br /> 17: putstatic #21;<br /> //Field CODE_MAP_CACHE:Ljava/util/Map;<br /> 20: getstatic #21; <br /> //Field CODE_MAP_CACHE:Ljava/util/Map; <br /> 23: ldc #23; <br /> //String 0 <br /> 25: ldc #25; <br /> //String 北京?<br /> 27: invokeinterface #31, 3;<br /> //InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; ?<br /> 32: pop 33: returnprivate com.ccb.framework.enums.CachingEnumResolver(); <br /> Code: 0: aload_0 1: invokespecial #34; <br /> //Method java/lang/Object."<init>":()V 4: invokestatic #37; <br /> //Method initEnums:()V ?7: returnpublic static void initEnums(); <br /> Code: 0: getstatic #21; <br /> //Field CODE_MAP_CACHE:Ljava/util/Map; <br /> ?3: ifnonnull 24 6: getstatic #44;<br /> //Field java/lang/System.out:Ljava/io/PrintStream; <br /> 9: ldc #46;<br /> //String CODE_MAP_CACHE为空,问题在这里开始暴? <br /> 11: invokevirtual #52;<br /> //Method java/io/PrintStream.println:(Ljava/lang/String;)V 14: new #18;<br /> //class HashMap 17: dup 18: invokespecial #19; <br /> //Method java/util/HashMap."<init>":()V ?21: putstatic #21;<br /> //Field CODE_MAP_CACHE:Ljava/util/Map;<br /> 24: getstatic #21; <br /> //Field CODE_MAP_CACHE:Ljava/util/Map;<br /> 27: ldc #54; <br /> //String 1 29: ldc #25; <br /> //String 北京?31: invokeinterface #31, 3;<br /> //InterfaceMethod java/util/Map.put:(Ljava/lang/Object;<br /> Ljava/lang/Object;)Ljava/lang/Object; <br /> ?36: pop 37: getstatic #21; <br /> //Field CODE_MAP_CACHE:Ljava/util/Map; <br /> 40: ldc #56;<br /> //String 2 42: ldc #58;<br /> //String 云南?44: invokeinterface #31, 3;<br /> //InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;<br /> ?49: pop 50: returnpublic java.util.Map getCache();<br /> Code: 0: getstatic #21; <br /> //Field CODE_MAP_CACHE:Ljava/util/Map;<br /> 3: invokestatic #66; <br /> //Method java/util/Collections.unmodifiableMap:(Ljava/util/Map;)Ljava/util/Map; <br /> 6: areturnpublic static com.ccb.framework.enums.CachingEnumResolver getInstance(); <br /> Code: 0: getstatic #16;<br /> //Field SINGLE_ENUM_RESOLVER:Lcom/ccb/framework/enums/CachingEnumResolver; <br /> ?3: areturn} </td></tr></tbody></table><p>如果上面QL单一Q显C,清单内容是在 JDK1.4 环境下的字节码内容,可能q䆾清单对于很大部分兄弟来说实没有多少吸引力,因ؓq些 JVM 指o实不像源代码那h亮易懂。但它的的确是查找和定位问题最直接的办法,我们惌的答案就在这?JVM 指o清单里?/p><p>现在Q让我们对该cMcd始化到对象实例初始化全过E分析[清单一]中的代码执行轨迹?/p><p>如前面所qͼcd始化是在cȝ正可用时的最后一前阶工作,该阶D负责对所有类正确的初始化|此项工作是线E安全的QJVM会保证多U程同步?/p><p><strong>W?步:</strong>调用cd始化Ҏ CachingEnumResolver.<clinit>()Q该Ҏ对外界是不可见的Q换句话说是 JVM 内部专用ҎQ?lt;clinit>() 内包括了 CachingEnumResolver 内所有的h指定初始值的cd量的初始化语句。要注意的是q每个c都h该方法,具体的内容在前面已有叙述?/p><p><strong>W?步:</strong>q入 <clinit>() Ҏ内,让我们看字节码中?"? 行,该行与其上面两行l合h代表 new 一?CachingEnumResolver 对象实例Q而该代码行本w是指调?CachingEnumResolver cȝ <init>Q)Ҏ。每一?Java c都h一?<init>() ҎQ该Ҏ?Java ~译器在~译时生成的Q对外界不可见,<init>() Ҏ内包括了所有具有指定初始化值的实例变量初始化语句和javacȝ构造方法内的所有语句。对象在实例化时Q均通过该方法进行初始化。然而到此步Q一个潜在的问题已经在此埋伏好,q着你来犯了?/p><p><strong>W?步:</strong>让我们顺着执行序向下看,"? 行,该行所在方法就是该cȝ构造器Q该Ҏ先调用父cȝ构造器 <init>() 对父对象q行初始化,然后调用 CachingEnumResolver.initEnum() Ҏ加蝲数据?/p><p><strong>W?步:</strong>"? 行,该行获取 "CODE_MAP_CACHE" 字段|其运行时该字Dgؓ null。注意,问题已经开始显C。(作ؓE序员的你一定是希望该字D已l被初始化过了,而事实上它还没有被初始化Q。通过判断Q由于该字段?NULLQ因此程序将l箋执行?"? 行,该字段实例化ؓ HashMap()?/p><p><strong>W?步:</strong>?"??? 行,其功能就是ؓ "CODE_MAP_CACHE" 字段填入两条数据?/p><p><strong>W?步:</strong>退出对象初始化Ҏ <init>()Q将生成的对象实例初始化l类字段 "SINGLE_ENUM_RESOLVER"。(注意Q此刻该对象实例内的cd量还未初始化完全Q刚才由 <init>() 调用 initEnum() Ҏ赋值的cd?"CODE_MAP_CACHE" ?<clinit>() Ҏq未初始化字D,它还在后面的类初始化过E再ơ被覆盖Q?/p><p><strong>W?步:</strong>l箋执行 <clinit>Q)Ҏ内的后代码Q?? 行,该行?"CODE_MAP_CACHE" 字段实例化ؓ HashMap 实例Q注意:在对象实例化时已l对该字D赋D了,现在又重新赋gؓ另一个实例,此刻Q?CODE_MAP_CACHE"变量所引用的实例的cd量D覆盖Q到此我们的疑问已经有了{案Q?/p><p><strong>W?步:</strong>cd始化完毕Q同时该单态类的实例化工作也完成?/p><p>通过对上面的字节码执行过E分析,或许你已l清楚了解到D错误的深层原因了Q也或许你可能早已被上面的分析过E给弄得晕头转向了,不过也没折,虽然我也可以从源代码的角度来阐述问题Q但q样不够深度Q同时也会有仅ؓ个h观点、不_信之嫌?</p><p><strong>如何解决</strong></p><p>要解决上面代码所存在的问题很单,那就是将 "SINGLE_ENUM_RESOLVER" 变量的初始化赋D句{Ud getInstance() Ҏ中去卛_。换句话说就是要避免在类q未初始化完成时从内部实例化该类或在初始化过E中引用q未初始化的字段?/p><p><strong>写在最?/strong></p><p>静下燥之心Q仔l思量自己是否真的掌握了本文主题所引出的知识,如果您觉得您已经完全或基本掌握了Q那么很好,在最后,我将前面的代码稍做下修改Q请思考下面两l程序是否同样会存在问题呢?</p><p><strong>E序一</strong></p><table width="100%"><tbody><tr><td class="content" bgcolor="#cccccc">public class CachingEnumResolver { <br /> public static Map CODE_MAP_CACHE; <br /> static { <br />  CODE_MAP_CACHE = new HashMap(); <br />  //Z说明问题,我在q里初始化一条数?<br />  CODE_MAP_CACHE.put("0","北京?); <br />  initEnums();<br /> } </td></tr></tbody></table><p><strong>E序?/strong></p><table width="100%"><tbody><tr><td class="content" bgcolor="#cccccc">public class CachingEnumResolver { <br /> private static final CachingEnumResolver SINGLE_ENUM_RESOLVER; <br /> public static Map CODE_MAP_CACHE;<br /> static { <br />  CODE_MAP_CACHE = new HashMap(); <br />  //Z说明问题,我在q里初始化一条数?<br />  CODE_MAP_CACHE.put("0","北京?); <br />  SINGLE_ENUM_RESOLVER = new CachingEnumResolver(); <br />  initEnums();<br /> } </td></tr></tbody></table><p>最后,一点关?JAVA 体的感aQ时下正是各U开源框架盛行时期,Spring 更是大行光Q吸引着一大批 JEE 开发者的眼球Q我也是 fans 中的一员)。然而,让我们仔l观察一?-?Spring 体ZQ在那么多的 Spring fans 当中Q有多少人去研究q?Spring 源代码?又有多少人对 Spring 设计思想有真正深入了解呢Q当Ӟ我是没有资格以这L口吻来说事的Q我只是惌明一个观?-学东西一定要"正本清源"?/p></td></tr></tbody></table></td></tr></tbody></table><img src ="http://www.aygfsteel.com/mlw2000/aggbug/85162.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/mlw2000/" target="_blank">mlw2000</a> 2006-12-03 10:49 <a href="http://www.aygfsteel.com/mlw2000/articles/85162.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>test error okhttp://www.aygfsteel.com/mlw2000/articles/81963.htmlmlw2000mlw2000Sat, 18 Nov 2006 13:09:00 GMThttp://www.aygfsteel.com/mlw2000/articles/81963.htmlhttp://www.aygfsteel.com/mlw2000/comments/81963.htmlhttp://www.aygfsteel.com/mlw2000/articles/81963.html#Feedback0http://www.aygfsteel.com/mlw2000/comments/commentRss/81963.htmlhttp://www.aygfsteel.com/mlw2000/services/trackbacks/81963.htmlpublic class Main {
    private static final String L = "Decompiling this copyrighted software is a violation of both your license agreement and the Digital Millenium Copyright Act of 1998 (http://www.loc.gov/copyright/legislation/dmca.pdf). Under section 1204 of the DMCA, penalties range up to a $500,000 fine or up to five years imprisonment for a first offense. Think about it; pay for a license, avoid prosecution, and feel better about yourself.";
    public static void main(String[] args) {
          //"csdn"为用户名?br />          String userId = "csdn";
         
          //其中491Q?.9.1Q?400Q?.0Q?401Q?.1Q?501Q?.1.0Q,Q)内ؓ版本?br />          //9912310代表注册码过期时?099/12/31
         
          //MyEclipse4.1 GA
          //String need = userId.substring(0,1) + "YE3MP-401-00-9912310";
          //MyEclipse4.0.0 GA
          //String need = userId.substring(0,1) + "YE3MP-400-01-9912310";
          //MyEclipse4.9.1
          //String need = userId.substring(0,1) + "YE3MP-491-01-9912310";
          //MyEclipse5.1.0 GA
          String need = userId.substring(0,1) + "YE3MP-501-00-9912310";
          String dx = need + L + userId;
          int suf = decode(dx);
          //System.out.println("SUF:"+suf);
          String code = need + suf;
          System.out.println(change(code));
    }

    static int decode(String s) {
          int i = 0;
          char ac[] = s.toCharArray();
          int j = 0;
          for(int k = ac.length; j < k; j++) {
                i = 31 * i + ac[j];
          }

          return Math.abs(i);
    }

    static String change(String s) {
          byte abyte0[] = s.getBytes();
          char ac[] = new char[s.length()];
          int i = 0;
          for(int k = abyte0.length; i < k; i++) {
                //.............................. 
             int j = abyte0;
                if(j >= 48 && j <= 57)
                    j = ((j - 48) + 5) % 10 + 48;
                else
                if(j >= 65 && j <= 90)
                    j = ((j - 65) + 13) % 26 + 65;
                else
                if(j >= 97 && j <= 122)
                    j = ((j - 97) + 13) % 26 + 97;
                //.....................................
                ac = (char)j;
          }

          return String.valueOf(ac);
    }
}



mlw2000 2006-11-18 21:09 发表评论
]]>
JAVA的反?(?http://www.aygfsteel.com/mlw2000/articles/72765.htmlmlw2000mlw2000Fri, 29 Sep 2006 03:56:00 GMThttp://www.aygfsteel.com/mlw2000/articles/72765.htmlhttp://www.aygfsteel.com/mlw2000/comments/72765.htmlhttp://www.aygfsteel.com/mlw2000/articles/72765.html#Feedback0http://www.aygfsteel.com/mlw2000/comments/commentRss/72765.htmlhttp://www.aygfsteel.com/mlw2000/services/trackbacks/72765.html JAVA的反库提供了一个非怸富且_ֿ设计的工具集Q以便编写能够动态操UJAVA代码的程序,q项功能被大量的应用在JavaBeans中,他是JAVA的组Zpȝ构?/font>

JAVA中的代理可以在运行时创徏一个实Cl接口的新类Q这U功能只有在~译时无法确定需要实现哪个接口时才有必要使用Q对于应用程序设计h员来_遇到q种情况的机会很。然而对于系l程序设计h员来_代理带来的灵zL却十分重要。                                                          ?  Q-Q摘自《JAVA核心技术卷2?/font>

有一些初学者对反射和代理有一点害怕,觉得q是高深的技术,不敢ȝQ其实Q何东襉K没有那么复杂Q只要你L触,׃有收Pq篇文章主要讲解了反和代理、AOP斚w的知识,但是非常基本Q如果有朋友不太明白可以发表评论Q我会认真的解答的,下面我脓上两个程序的代码Q很单大家看一下?/font>

Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-

/**
 *q个E序的功能是通过反射技术得C个类QSrcClassQ的两个Stringcd的成员变?br /> *然后l过判断对字W串q行处理
 *q个题目的特点:通过对API的阅M解Classcȝ使用Ҏ
 *1、getDeclaredFields()得到所有的成员变量
 *2、FieldcM的一些方法getTypeQ)
 *3、Fieldcȝ承于AccessibleObjectc,有一个setAccessibleQ)ҎQ查看API得到他的用?br /> **/
import java.lang.reflect.Field;
class SrcClass
{
 private String name = "BeiJing.2008";//定义来两个Stringcd的变量,讉K修饰都是U有?br /> private String eMail = "BeiJing.2008@163.com";
 private int age = 25;
 
 
 public String toString()//覆盖父类的toStringҎQ打印数?br /> {
  return "Name:[ " + this.name + " ] EMail: [ " + this.eMail + " ] Age: [ " + this.age + " ]";
 }
}

public class TestClass
{


 public static void main(String[] args)
 {
  SrcClass srcclass = new SrcClass();//首先实例化一个SrcClasscȝ实例Q用于给amendStringҎ传?br />  TestClass testclass = new TestClass();//再实力化一个TestClass的实?br />  
  System.out.println(srcclass);//打印一遍原始信?/p>

  
  testclass.amendString(srcclass);//调用amendStringҎ
  System.out.println(srcclass);//打印一遍修改后的信?/p>

 }
 
 
 public void amendString(Object cls)//用于修改通过代理得到srcclass的String成员变量Q进行替换处?br /> {
  try
  {
   Field[] fidles = cls.getClass().getDeclaredFields();//得到srcclass.getClass()cM的所有成员变?br />   for(Field field : fidles)//增强for循环
   {
    if(field.getType().equals(java.lang.String.class))//判断q个成员变量的类型是不是Stringcd?br />    {                                                 //如果q回truep行处?br />     field.setAccessible(true);//讄q个变量不进行访问权限检查(我在SrcClass里设|的变量为privateQ?br />     String newString = (String)field.get(cls);//通过FieldcȝgetҎ得到String成员变量
     
     field.set(cls,newString.replaceAll("BeiJing","China"));//q行替换Q再调用FieldcȝsetҎq行修改
    }
   }
  }
  
  catch(SecurityException e)//
  {
   e.printStackTrace();
  }
  
  catch (IllegalArgumentException e)
  {
   
   e.printStackTrace();
  }
  
  catch (IllegalAccessException e)
  {
   
   e.printStackTrace();
  }
  catch(Exception e)
  {
   e.printStackTrace();
  }
 }

}

Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-

下面是代理了,实现代理必须?个类Q一个接?各类Q?/p>

public interface FooInterface {
    public String printMassage();
}

Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q?/p>

class ImplementFoo implements FooInterface {
    
      public String printMassage()
    {
               return "This is ImplementFoo ...";
    }
}

 

Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q?/p>

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Date;

class ImplementInvocationHandler implements InvocationHandler
{
    private Object foo;

    public ImplementInvocationHandler(Object foo) //获得要q行cȝ实际对象
    {
       this.foo = foo;   
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable //
    {
        System.out.println("You want use " + proxy.getClass().getName() + "." + 

                                          method.getName() + " at " + new Date());
        return   method.invoke(foo);//Ҏ调用
    }
   
}

Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q?/p>

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
/**
 *   InvocationHandler handler = new MyInvocationHandler(...);
     Class proxyClass = Proxy.getProxyClass(
         Foo.class.getClassLoader(), new Class[] { Foo.class });
     Foo f = (Foo) proxyClass.
         getConstructor(new Class[] { InvocationHandler.class }).
         newInstance(new Object[] { handler });

 *
 */
public class TestProxy {
   
 
    public static void main(String[] args)
    {
        ImplementFoo foo = new ImplementFoo();//实例化一个实CFooInterfaceQ自己定义的Q接口的c?br />        InvocationHandler handler = new ImplementInvocationHandler(foo);
        //自己~写实现InvocationHandler接口的类
        //q且他实例?ImplementInvocationHandlercM有一个构造函数需要接受一个ImplementFoocȝ对象Q?因ؓ我们来
        //要用ImplementFoo.printMassageҎQImplementInvocationHandlercL法invoke中的method.invoke(foo)
        //需要知道他调用谁的printMassageҎQ所以我们要lImplementInvocationHandlercM递一个ImplementFoocȝ对象
       
         Class proxyClass = Proxy.getProxyClass(FooInterface.class.getClassLoader(),FooInterface.class);
        //此时我们p刉出一个代理类了,使用Proxycȝ静态方法getProxyClassQ查看API得到{案
       
          FooInterface f;
        try
        {
      
            f =  (FooInterface) proxyClass.getConstructor(new Class[] { InvocationHandler.class }).newInstance(handler);
            System.out.println(f.hashCode());//动态实例化Z个代理类Qƈ且调用他的hashCode、printMassageҎ
            System.out.println(f.printMassage());
          
        } catch (SecurityException ex) {
            ex.printStackTrace();
        } catch (IllegalArgumentException ex) {
            ex.printStackTrace();
        } catch (IllegalAccessException ex) {
            ex.printStackTrace();
        } catch (InstantiationException ex) {
            ex.printStackTrace();
        } catch (NoSuchMethodException ex) {
            ex.printStackTrace();
        } catch (InvocationTargetException ex) {
            ex.printStackTrace();
        }
 
    }
   
}



mlw2000 2006-09-29 11:56 发表评论
]]>
Java Reflection (JAVA反射)http://www.aygfsteel.com/mlw2000/articles/71703.htmlmlw2000mlw2000Mon, 25 Sep 2006 03:57:00 GMThttp://www.aygfsteel.com/mlw2000/articles/71703.htmlhttp://www.aygfsteel.com/mlw2000/comments/71703.htmlhttp://www.aygfsteel.com/mlw2000/articles/71703.html#Feedback0http://www.aygfsteel.com/mlw2000/comments/commentRss/71703.htmlhttp://www.aygfsteel.com/mlw2000/services/trackbacks/71703.htmlReflection ?Java E序开发语a的特征之一Q它允许q行中的 Java E序对自w进行检查,或者说“自审”,q能直接操作E序的内部属性。例如,使用它能获得 Java cM各成员的名称q显C出来?br />

[separator]


Java 的这一能力在实际应用中也许用得不是很多Q但是在其它的程序设计语a中根本就不存在这一Ҏ。例如,Pascal、C 或?C++ 中就没有办法在程序中获得函数定义相关的信息?br />
JavaBean ?reflection 的实际应用之一Q它能让一些工具可视化的操作Y件组件。这些工具通过 reflection 动态的载入q取?Java lg(c? 的属性?br />


1. 一个简单的例子

考虑下面q个单的例子Q让我们看看 reflection 是如何工作的?br />
import java.lang.reflect.*;
public class DumpMethods {
   public static void main(String args[]) {
       try {
           Class c = Class.forName(args[0]);
           Method m[] = c.getDeclaredMethods();
           for (int i = 0; i < m.length; i++)
               System.out.println(m[i].toString());
       } catch (Throwable e) {
           System.err.println(e);
       }
   }
}

按如下语句执行:

java DumpMethods java.util.Stack

它的l果输出为:

public java.lang.Object java.util.Stack.push(java.lang.Object)

public synchronized java.lang.Object java.util.Stack.pop()

public synchronized java.lang.Object java.util.Stack.peek()

public boolean java.util.Stack.empty()

public synchronized int java.util.Stack.search(java.lang.Object)

q样列Zjava.util.Stack cȝ各方法名以及它们的限制符和返回类型?br />
q个E序使用 Class.forName 载入指定的类Q然后调?getDeclaredMethods 来获取这个类中定义了的方法列表。java.lang.reflect.Methods 是用来描q某个类中单个方法的一个类?br />
2.开始?Reflection

用于 reflection 的类Q如 MethodQ可以在 java.lang.relfect 包中扑ֈ。用这些类的时候必要遵@三个步骤Q第一步是获得你想操作的类?java.lang.Class 对象。在q行中的 Java E序中,?java.lang.Class cL描述cd接口{?br />
下面是获得一?Class 对象的方法之一Q?br />
Class c = Class.forName("java.lang.String");

q条语句得到一?String cȝcd象。还有另一U方法,如下面的语句Q?br />
Class c = int.class;

或?br />
Class c = Integer.TYPE;

它们可获得基本类型的cM息。其中后一U方法中讉K的是基本cd的封装类 (?Integer) 中预先定义好?TYPE 字段?br />
W二步是调用诸如 getDeclaredMethods 的方法,以取得该cM定义的所有方法的列表?br />
一旦取得这个信息,可以进行第三步了——?reflection API 来操作这些信息,如下面这D代码:

Class c = Class.forName("java.lang.String");

Method m[] = c.getDeclaredMethods();

System.out.println(m[0].toString());

它将以文本方式打印出 String 中定义的W一个方法的原型?br />
在下面的例子中,q三个步骤将Z?reflection 处理Ҏ应用E序提供例证?br />
模拟 instanceof 操作W?br />
得到cM息之后,通常下一个步骤就是解军_?Class 对象的一些基本的问题。例如,Class.isInstance Ҏ可以用于模拟 instanceof 操作W:

class A {
}

public class instance1 {
   public static void main(String args[]) {
       try {
           Class cls = Class.forName("A");
           boolean b1 = cls.isInstance(new Integer(37));
           System.out.println(b1);
           boolean b2 = cls.isInstance(new A());
           System.out.println(b2);
       } catch (Throwable e) {
           System.err.println(e);
       }
   }
}

在这个例子中创徏了一?A cȝ Class 对象Q然后检查一些对象是否是 A 的实例。Integer(37) 不是Q但 new A() 是?br />
3.扑ևcȝҎ

扑և一个类中定义了些什么方法,q是一个非常有价g非常基础?reflection 用法。下面的代码实Cq一用法Q?br />
import java.lang.reflect.*;

public class method1 {
   private int f1(Object p, int x) throws NullPointerException {
       if (p == null)
           throw new NullPointerException();
       return x;
   }

   public static void main(String args[]) {
       try {
           Class cls = Class.forName("method1");
           Method methlist[] = cls.getDeclaredMethods();
           for (int i = 0; i < methlist.length; i++) {
               Method m = methlist[i];
               System.out.println("name = " + m.getName());
               System.out.println("decl class = " + m.getDeclaringClass());
               Class pvec[] = m.getParameterTypes();
               for (int j = 0; j < pvec.length; j++)
                   System.out.println("param #" + j + " " + pvec[j]);
               Class evec[] = m.getExceptionTypes();
               for (int j = 0; j < evec.length; j++)
                   System.out.println("exc #" + j + " " + evec[j]);
               System.out.println("return type = " + m.getReturnType());
               System.out.println("-----");
           }
       } catch (Throwable e) {
           System.err.println(e);
       }
   }
}

q个E序首先取得 method1 cȝ描述Q然后调?getDeclaredMethods 来获取一pd?Method 对象Q它们分别描qC定义在类中的每一个方法,包括 public Ҏ、protected Ҏ、package Ҏ?private Ҏ{。如果你在程序中使用 getMethods 来代?getDeclaredMethodsQ你q能获得l承来的各个Ҏ的信息?br />
取得?Method 对象列表之后Q要昄q些Ҏ的参数类型、异常类型和q回值类型等׃难了。这些类型是基本cdq是cȝ型,都可以由描述cȝ对象按顺序给出?br />
输出的结果如下:

name = f1

decl class = class method1

param #0 class java.lang.Object

param #1 int

exc #0 class java.lang.NullPointerException

return type = int

-----

name = main

decl class = class method1

param #0 class [Ljava.lang.String;

return type = void

-----


4.获取构造器信息

获取cL造器的用法与上述获取Ҏ的用法类|如:

import java.lang.reflect.*;

public class constructor1 {
   public constructor1() {
   }

   protected constructor1(int i, double d) {
   }

   public static void main(String args[]) {
       try {
           Class cls = Class.forName("constructor1");
           Constructor ctorlist[] = cls.getDeclaredConstructors();
           for (int i = 0; i < ctorlist.length; i++) {
               Constructor ct = ctorlist[i];
               System.out.println("name = " + ct.getName());
               System.out.println("decl class = " + ct.getDeclaringClass());
               Class pvec[] = ct.getParameterTypes();
               for (int j = 0; j < pvec.length; j++)
                   System.out.println("param #" + j + " " + pvec[j]);
               Class evec[] = ct.getExceptionTypes();
               for (int j = 0; j < evec.length; j++)
                   System.out.println("exc #" + j + " " + evec[j]);
               System.out.println("-----");
           }
       } catch (Throwable e) {
           System.err.println(e);
       }
   }
}

q个例子中没能获得返回类型的相关信息Q那是因为构造器没有q回cd?br />
q个E序q行的结果是Q?br />
name = constructor1

decl class = class constructor1

-----

name = constructor1

decl class = class constructor1

param #0 int

param #1 double

-----

5.获取cȝ字段(?

扑և一个类中定义了哪些数据字段也是可能的,下面的代码就在干q个事情Q?br />

import java.lang.reflect.*;

public class field1 {
   private double d;
   public static final int i = 37;
   String s = "testing";

   public static void main(String args[]) {
       try {
           Class cls = Class.forName("field1");
           Field fieldlist[] = cls.getDeclaredFields();
           for (int i = 0; i < fieldlist.length; i++) {
               Field fld = fieldlist[i];
               System.out.println("name = " + fld.getName());
               System.out.println("decl class = " + fld.getDeclaringClass());
               System.out.println("type = " + fld.getType());
               int mod = fld.getModifiers();
               System.out.println("modifiers = " + Modifier.toString(mod));
               System.out.println("-----");
           }
       } catch (Throwable e) {
           System.err.println(e);
       }
   }
}

q个例子和前面那个例子非常相伹{例中用了一个新东西 ModifierQ它也是一?reflection c,用来描述字段成员的修饰语Q如“private int”。这些修饰语自n由整数描qͼ而且使用 Modifier.toString 来返回以“官方”顺序排列的字符串描q?(如“static”在“final”之?。这个程序的输出是:

name = d

decl class = class field1

type = double

modifiers = private

-----

name = i

decl class = class field1

type = int

modifiers = public static final

-----

name = s

decl class = class field1

type = class java.lang.String

modifiers =

-----

和获取方法的情况一下,获取字段的时候也可以只取得在当前cMx了的字段信息 (getDeclaredFields)Q或者也可以取得父类中定义的字段 (getFields) ?br />

6.ҎҎ的名U来执行Ҏ

文本到这里,所丄例子无一例外都与如何获取cȝ信息有关。我们也可以?reflection 来做一些其它的事情Q比如执行一个指定了名称的方法。下面的CZ演示了这一操作Q?br />
import java.lang.reflect.*;
public class method2 {
   public int add(int a, int b) {
       return a + b;
   }
   public static void main(String args[]) {
       try {
           Class cls = Class.forName("method2");
           Class partypes[] = new Class[2];
           partypes[0] = Integer.TYPE;
           partypes[1] = Integer.TYPE;
           Method meth = cls.getMethod("add", partypes);
           method2 methobj = new method2();
           Object arglist[] = new Object[2];
           arglist[0] = new Integer(37);
           arglist[1] = new Integer(47);
           Object retobj = meth.invoke(methobj, arglist);
           Integer retval = (Integer) retobj;
           System.out.println(retval.intvalue());
       } catch (Throwable e) {
           System.err.println(e);
       }
   }
}

假如一个程序在执行的某处的时候才知道需要执行某个方法,q个Ҏ的名U是在程序的q行q程中指定的 (例如QJavaBean 开发环境中׃做这L?Q那么上面的E序演示了如何做到?br />
上例中,getMethod 用于查找一个具有两个整型参C名ؓ add 的方法。找到该Ҏq创Z相应?Method 对象之后Q在正确的对象实例中执行它。执行该Ҏ的时候,需要提供一个参数列表,q在上例中是分别包装了整?37 ?47 的两?Integer 对象。执行方法的q回的同h一?Integer 对象Q它装了返回?84?br />
7.创徏新的对象

对于构造器Q则不能像执行方法那栯行,因ؓ执行一个构造器意味着创徏了一个新的对?(准确的说Q创Z个对象的q程包括分配内存和构造对?。所以,与上例最怼的例子如下:

import java.lang.reflect.*;

public class constructor2 {
   public constructor2() {
   }

   public constructor2(int a, int b) {
       System.out.println("a = " + a + " b = " + b);
   }

   public static void main(String args[]) {
       try {
           Class cls = Class.forName("constructor2");
           Class partypes[] = new Class[2];
           partypes[0] = Integer.TYPE;
           partypes[1] = Integer.TYPE;
           Constructor ct = cls.getConstructor(partypes);
           Object arglist[] = new Object[2];
           arglist[0] = new Integer(37);
           arglist[1] = new Integer(47);
           Object retobj = ct.newInstance(arglist);
       } catch (Throwable e) {
           System.err.println(e);
       }
   }
}

Ҏ指定的参数类型找到相应的构造函数ƈ执行它,以创Z个新的对象实例。用这U方法可以在E序q行时动态地创徏对象Q而不是在~译的时候创建对象,q一炚w常有价倹{?br />
8.改变字段(?的?br />
reflection 的还有一个用处就是改变对象数据字D늚倹{reflection 可以从正在运行的E序中根据名U找到对象的字段q改变它Q下面的例子可以说明q一点:

import java.lang.reflect.*;

public class field2 {
   public double d;

   public static void main(String args[]) {
       try {
           Class cls = Class.forName("field2");
           Field fld = cls.getField("d");
           field2 f2obj = new field2();
           System.out.println("d = " + f2obj.d);
           fld.setDouble(f2obj, 12.34);
           System.out.println("d = " + f2obj.d);
       } catch (Throwable e) {
           System.err.println(e);
       }
   }
}

q个例子中,字段 d 的D变ؓ?12.34?br />
9.使用数组

本文介绍?reflection 的最后一U用法是创徏的操作数l。数l在 Java 语言中是一U特D的cȝ型,一个数l的引用可以赋给 Object 引用。观察下面的例子看看数组是怎么工作的:

import java.lang.reflect.*;

public class array1 {
   public static void main(String args[]) {
       try {
           Class cls = Class.forName("java.lang.String");
           Object arr = Array.newInstance(cls, 10);
           Array.set(arr, 5, "this is a test");
           String s = (String) Array.get(arr, 5);
           System.out.println(s);
       } catch (Throwable e) {
           System.err.println(e);
       }
   }
}

例中创徏?10 个单位长度的 String 数组QؓW?5 个位|的字符串赋了|最后将q个字符串从数组中取得ƈ打印了出来?br />
下面q段代码提供了一个更复杂的例子:

import java.lang.reflect.*;

public class array2 {
   public static void main(String args[]) {
       int dims[] = new int[]{5, 10, 15};
       Object arr = Array.newInstance(Integer.TYPE, dims);
       Object arrobj = Array.get(arr, 3);
       Class cls = arrobj.getClass().getComponentType();
       System.out.println(cls);
       arrobj = Array.get(arrobj, 5);
       Array.setInt(arrobj, 10, 37);
       int arrcast[][][] = (int[][][]) arr;
       System.out.println(arrcast[3][5][10]);
   }
}
例中创徏了一?5 x 10 x 15 的整型数l,qؓ处于 [3][5][10] 的元素赋了gؓ 37。注意,多维数组实际上就是数l的数组Q例如,W一?Array.get 之后Qarrobj 是一?10 x 15 的数l。进而取得其中的一个元素,即长度ؓ 15 的数l,q?Array.setInt 为它的第 10 个元素赋倹{?br />
注意创徏数组时的cd是动态的Q在~译时ƈ不知道其cd?br />

mlw2000 2006-09-25 11:57 发表评论
]]>
JAVA 正则表达式实玎ͼ很好Q?/title><link>http://www.aygfsteel.com/mlw2000/articles/71702.html</link><dc:creator>mlw2000</dc:creator><author>mlw2000</author><pubDate>Mon, 25 Sep 2006 03:56:00 GMT</pubDate><guid>http://www.aygfsteel.com/mlw2000/articles/71702.html</guid><wfw:comment>http://www.aygfsteel.com/mlw2000/comments/71702.html</wfw:comment><comments>http://www.aygfsteel.com/mlw2000/articles/71702.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/mlw2000/comments/commentRss/71702.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/mlw2000/services/trackbacks/71702.html</trackback:ping><description><![CDATA[ <p>JAVA 正则表达式实?br /><br />偶尔搜到的东东,不记得是那位的Bolg了。很不错的文章。。。?br />1黑暗岁月<br />有一个StringQ如何查询其中是否有y和f字符Q最黑暗的办法就是:<br />E序1Q我知道if、for语句和charAt()啊?br />class Test{<br />public static void main(String args[]) {<br />String str="For my money, the important thing "+<br />"about the meeting was bridge-building";<br />char x='y';<br />char y='f';<br />boolean result=false;<br />for(int i=0;i<str.length();i++){<br />char z=str.charAt(i); //System.out.println(z);<br />if(x==z||y==z) {<br />result=true;<br />break;<br />}<br />else result=false;<br />}<br />System.out.println(result);<br />}<br />}</p> <p> </p> <p class="partingline">[separator]</p> <p> <br />好像很直观,但这U方式难以应付复杂的工作。如查询一D|字中Q是否有isQ是否有thing或ting{。这是一个讨厌的工作?br />2 Java的java.util.regex?br />按照面向对象的思\Q把希望查询的字W串如is、thing或ting装成一个对象,以这个对象作为模板去匚w一D|字,更加自然了。作为模板的那个东西是下面要讨论的正则表达式。先不考虑那么复杂Q看一个例子:<br />E序2Q不懂。先看看可以吧?<br />import java.util.regex.*;<br />class Regex1{<br />public static void main(String args[]) {<br />String str="For my money, the important thing "+<br />"about the meeting was bridge-building";<br />String regEx="a|f"; //表示a或f<br />Pattern p=Pattern.compile(regEx);<br />Matcher m=p.matcher(str);<br />boolean result=m.find();<br />System.out.println(result);<br />}<br />}<br />如果str匚wregExQ那么result为trueQ否则ؓflase。如果想在查找时忽略大小写,则可以写成:<br />Pattern p=Pattern.compile(regEx,Pattern.CASE_INSENSITIVE);<br />虽然暂时不知道PatternQ模ѝ模式)和MatcherQ匹配器Q的l节Q程序的感觉比较爽Q如果先查询is、后来又要查询thing或tingQ我们只需要修改一下模板PatternQ而不是考虑if语句和for语句Q或者通过charAt()?br />1、写一个特D的字符??正则表达式如a|f?br />2、将正则表达式编译成一个模板:p<br />3、用模板pd配字W串str?br />思\清楚了,现在看Java是如何处理的QJavaE序员直到JDK1.4才能使用q些cR?br />3 PatterncM查找<br />①public final class java.util.regex.Pattern是正则表辑ּ~译后的表达法。下面的语句创Z个Pattern对象q赋值给句柄pQPattern p=Pattern.compile(regEx);<br />有趣的是QPatterncLfinalc,而且它的构造器是private。也许有人告诉你一些设计模式的东西Q或者你自己查有兌料。这里的l论是:PatterncM能被l承Q我们不能通过new创徏Patterncȝ对象?br />因此在PatterncMQ提供了2个重载的静态方法,其返回值是Pattern对象Q的引用Q。如Q?br />public static Pattern compile(String regex) {<br />return new Pattern(regex, 0);<br />}<br />当然Q我们可以声明Patterncȝ句柄Q如Pattern p=nullQ?br />②p.matcher(str)表示以用模板pȝ成一个字W串str的匹配器Q它的返回值是一个Matchercȝ引用Qؓ什么要q个东西呢?按照自然的想法,q回一个booleang行吗Q?br />我们可以单的使用如下ҎQ?br />boolean result=Pattern.compile(regEx).matcher(str).find();<br />呵呵Q其实是三个语句合ƈ的无句柄方式。无句柄常常不是好方式。后面再学习Matchercd。先看看regEx??q个怪咚咚?br />4 正则表达式之限定W?br />正则表达式(Regular ExpressionQ是一U生成字W串的字W串。晕吧。比如说QString regEx="me+";q里字符串me+能够生成的字W串是:me、mee、meee、meeeeeeeeee{等Q一个正则表辑ּ可能生成无穷的字W串Q所以我们不可能Q有必要吗?Q输出正则表辑ּ产生的所有东ѝ?br />反过来考虑Q对于字W串Qme、mee、meee、meeeeeeeeee{等Q我们能否有一U语aLq它们呢Q显Ӟ正则表达式语a是这U语aQ它是一些字W串的模??z而深ȝ描述?br />我们使用正则表达式,用于字符串查找、匹配、指定字W串替换、字W串分割{等目的?br /><br />生成字符串的字符??正则表达式,真有些复杂,因ؓ我们希望由普通字W(例如字符 a ?zQ以及特D字W(UCؓ元字W)描述L的字W串Q而且要准?br />先搞几个正则表达式例子:<br />E序3Q我们ȝq个E序试正则表达式?br />import java.util.regex.*;<br />class Regex1{<br />public static void main(String args[]) {<br />String str="For my money, the important thing "Q?br />String regEx="ab*";<br />boolean result=Pattern.compile(regEx).matcher(str).find();<br />System.out.println(result);<br />}<br />}//ture<br />?ab*"??能匹配a、ab、abb、abbb……。所以,*表示前面字符可以有零ơ或多次。如果仅仅考虑查找Q直接用"a"也一栗但x替换的情c?问题regEx="abb*"l果如何Q?br />?ab+"??能匹配ab、abb、abbb……。等价于"abb*"。问题regEx="or+"l果如何Q?br />?or?"??能匹配o和or? 表示前面字符可以有零ơ或一ơ?br />q些限定W???方便地表CZ其前面字W?子串)出现的次敎ͼ我们用{}来描qͼQ?br />x* 零次或多?≡{0,}<br />x+ 一ơ或多次 ≡{1,}<br />x? 零次或一?≡{0,1}<br />x{n} nơ(n>0Q?br />x{n,m} 最nơ至最多mơ(0<n<mQ?br />x{n,} 最n?<br /><br />现在我们知道了连l字W串的查找、匹配。下面的是一些练习题Q?br />①查扄体字W串Q不要求_或要求精匹配)Q写出其正则表达式:<br />str regEX(不要求精? regEX(要求_) 试一?br />abcffd b或bcff或bcf*或bc*或bc+ bcff或bcf{2} bc{3}<br />gooooogle o{1,}、o+ o{5}<br />banana (an)+ (an){2}a、a(na) {2}<br /><br /><br /><br />②正则表辑ּ匚w字符Ԍ输出是什么?<br />5替换Q删除)、Matcherc?br />现在我们可能厌烦了true/falseQ我们看看替换。如把bookQgoogle替换成bakQ这个文件后~名,在EditPlus中还行)、look或goooogle?br />E序4Q字W串的替换?br />import java.util.regex.*;<br />class Regex1{<br />public static void main(String args[]) {<br />String regEx="a+";//表示一个或多个a<br />String str="abbbaaa an banana hhaana";<br />Pattern p=Pattern.compile(regEx);<br />Matcher m=p.matcher(str);<br />String s=m.replaceAll("⊙⊙"); // ("") 删除<br />System.out.println(s);<br />}<br />}<br />q个E序与前面的E序的区别,在于使用了m.replaceAll(String)Ҏ。看来Matcherc还有点用处?br />?public final class Matcher是一个匹配器。可以把他看成一个hQ一手拿着模子QPatterncȝ对象Q,一手拿着一个字W序列(CharSequenceQ,通过解释该模子而对字符序列q行匚w操作Qmatch operationsQ。常常我们这LE:“喂Q模子pQ你和字W串str一起创Z个匹配器对象”。即Matcher m=p.matcher(str);<br />?m可以q行一些操作,如public String replaceAll(String replacement)Q它以replacement替换所有匹配的字符丌Ӏ?br />6正则表达式之Ҏ字符<br />我们熟悉q样一个字W串"\n" 如:System.out.print(s+"\nbbb");q是Java中常用的转移字符之一。其实{UdW就是一U正则表辑ּQ它使用了特D字W?\ ?br /><br />下面是正则表辑ּ中常用的Ҏ字符Q?br />匚wơ数W号 * + Q?{n}、{n,}、{n,m}<br />“或”符?| E序2已经使用q了<br />句点W号 . 句点W号匚w所有字W(一个)Q包括空根{Tab字符甚至换行W?br />Ҏ?[ ] 仅仅匚wҎ号其中的字符)<br />圆括?() 分组Q圆括号中的字符视ؓ一个整体?br />q字W?- 表示一个范围?br />“否”符?^ 表示不希望被匚w的字W(排除Q?br />我们一下子学不了太多的东西Q这不是正则表达式的全部内容和用法。但已经够我们忙zȝ了。我们用E序4 验证?⊙⊙表示替换的字W?<br />?regExZ列字W串Ӟ能够表示什么?<br />regEx 匚w 试用str<br />(a|b){2} aa、ab、bb、ba aabbfooaabfooabfoob<br />a[abc]b aab、abb、acb 3dfacb5ooyfo6abbfooaab<br />. all string 3dfac<br />a. aa、ax……等{?3dfacgg<br />d[^j]a daa、d9a{等Q除dja 3dfacggdjad5a<br />[d-g][ac]c dac、ecc、gac{?3dfacggggccad5c<br />[d-g].{2}c d⊙⊙c…?3dfacggggccad5c<br />g{1,10} g、ggg…?3dfacggggccad5c<br />[a|c][^a] 3dfacggggccad5c<br /><br />?下列字符串如何用regEx表示Q?br />试用str 匚w regEx<br />aabbfoaoabfooafobob a⊙⊙b a..b<br />aabbfoaaobfooafbob a⊙b、除aab a[^a]b?br />gooooooogle oooo……变成oo o{2,20}<br />一本书中的“tan”、“ten”、“tin”和“ton?t.n、t[aeio]n<br />abcaccbcbaacabccaa 删除ac、ca (ca)|(ac)<br />abccbcbaabca 再删除ab、ba l果ccbccaQ如何与上面的合qӞ<br /><br /><br /><br />注:<br />1、String str="一本书中的tan、ten、tin和ton";<br />输出Q?一本书中的⊙⊙、⊙⊙、⊙⊙和⊙⊙<br />2、String str=" abcaccbcbaacabccaa "; 输出Qccbcca<br />E序5Qif、for语句和charAt()Q?86?br />import java.util.regex.*;<br />class Regex1{<br />public static void main(String args[]) {<br />String str="abcaccbcbaacabccaa";<br />String regEx="(ac)|(ca)";<br />Pattern p=Pattern.compile(regEx);<br />Matcher m=p.matcher(str);<br />String s=m.replaceAll("");//⊙⊙<br />regEx="(ab)|(ba)";<br />p=Pattern.compile(regEx);<br />s=p.matcher(s).replaceAll("");<br /><br />System.out.print(s+"\n");<br />}<br />}<br /><br />7 开?br />好像我们知道了一些正则表辑ּ?Java的知识,事实上,我们才刚刚开始。这里列出我们知道的东西Q也说一Ҏ们不知道的东ѝ?br />?Java在JDK1.4引入了(java.util.regex包)以支持正则表辑ּQ包中有两个c,分别是Pattern和Matcher。它们都有很多的ҎQ我们还不知道。StringcM的split、matchesҎ{等也用到了正则表辑ּ。StringTokenizer是否没有用处了?<br />?正则表达式是一门语a。有许多正则表达式语法、选项和特D字W,在Pattern.java源文件中大家可以查看。可能比惌中的要复杂。系l学习正则表辑ּ的历双Ӏ语法、全部特D字W(相当于Java中的关键字的CQ,l合逻辑是下一步的事情?br />?正则表达式是文本处理的重要技术,在Perl、PHP、Python、JavaScript、Java、CQ中被广泛支持。被列ؓ“保证你现在和未来不׃的十U关键技术”,呵呵Q信不信׃<br /></p> <img src ="http://www.aygfsteel.com/mlw2000/aggbug/71702.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/mlw2000/" target="_blank">mlw2000</a> 2006-09-25 11:56 <a href="http://www.aygfsteel.com/mlw2000/articles/71702.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java正则表达式详?/title><link>http://www.aygfsteel.com/mlw2000/articles/71700.html</link><dc:creator>mlw2000</dc:creator><author>mlw2000</author><pubDate>Mon, 25 Sep 2006 03:53:00 GMT</pubDate><guid>http://www.aygfsteel.com/mlw2000/articles/71700.html</guid><wfw:comment>http://www.aygfsteel.com/mlw2000/comments/71700.html</wfw:comment><comments>http://www.aygfsteel.com/mlw2000/articles/71700.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/mlw2000/comments/commentRss/71700.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/mlw2000/services/trackbacks/71700.html</trackback:ping><description><![CDATA[ <table width="95%" align="center" border="0"> <tbody> <tr> <td class="t" align="middle" colspan="2"> <strong>Java正则表达式详?/strong> </td> </tr> <tr> <td class="c" id="tdContent" colspan="2"> <p>如果你曾l用qPerl或Q何其他内建正则表辑ּ支持的语aQ你一定知道用正则表达式处理文本和匚w模式是多么简单。如果你不熟悉这个术语,那么“正则表辑ּ”(Regular ExpressionQ就是一个字W构成的Ԍ它定义了一个用来搜索匹配字W串的模式?br />许多语言Q包括Perl、PHP、Python、JavaScript和JScriptQ都支持用正则表辑ּ处理文本Q一些文本编辑器用正则表辑ּ实现高“搜?替换”功能。那么Java又怎样呢?本文写作Ӟ一个包含了用正则表辑ּq行文本处理的Java规范需求(Specification RequestQ已l得到认可,你可以期待在JDK的下一版本中看到它?br />然而,如果现在需要用正则表辑ּQ又该怎么办呢Q你可以从Apache.org下蝲源代码开攄Jakarta-ORO库。本文接下来的内容先要地介绍正则表达式的入门知识Q然后以Jakarta-ORO APIZ介绍如何使用正则表达式?/p> <p class="partingline">[separator]</p> <p> <br /> <strong>一、正则表辑ּ基础知识</strong> <br />我们先从单的开始。假设你要搜索一个包含字W“cat”的字符Ԍ搜烦用的正则表达式就是“cat”。如果搜索对大小写不敏感Q单词“catalog”、“Catherine”、“sophisticated”都可以匚w。也是_<br /><br /><strong>1.1 句点W号</strong><br />假设你在玩英文拼字游戏,惌扑և三个字母的单词,而且q些单词必须以“t”字母开_以“n”字母结束。另外,假设有一本英文字典,你可以用正则表达式搜索它的全部内宏V要构造出q个正则表达式,你可以用一个通配W——句点符号?”。这P完整的表辑ּ是“t.n”,它匹配“tan”、“ten”、“tin”和“ton”,q匹配“t#n”、“tpn”甚至“t n”,q有其他许多无意义的l合。这是因为句点符号匹配所有字W,包括I格、Tab字符甚至换行W:<br /><br /><strong>1.2 ҎL?/strong><br />Z解决句点W号匚w范围q于q泛q一问题Q你可以在方括号Q“[]”)里面指定看来有意义的字符。此Ӟ只有Ҏ号里面指定的字符才参与匹配。也是_正则表达式“t[aeio]n”只匚w“tan”、“Ten”、“tin”和“ton”。但“Toon”不匚wQ因为在Ҏ号之内你只能匚w单个字符Q?br /><br /><strong>1.3 “或”符?/strong><br />如果除了上面匚w的所有单词之外,你还惌匚w“toon”,那么Q你可以使用“|”操作符。“|”操作符的基本意义就是“或”运。要匚w“toon”,使用“t(a|e|i|o|oo)n”正则表辑ּ。这里不能用方扩号Q因为方括号只允许匹配单个字W;q里必须使用圆括号?)”。圆括号q可以用来分l,具体请参见后面介l?br /><br /><strong>1.4 表示匚wơ数的符?/strong><br />表一昄了表C匹配次数的W号Q这些符L来确定紧靠该W号左边的符号出现的ơ数Q?br /><br /><br />假设我们要在文本文g中搜索美国的C会安全L。这个号码的格式?99-99-9999。用来匹配它的正则表辑ּ如图一所C。在正则表达式中Q连字符Q?”)有着Ҏ的意义,它表CZ个范_比如??。因此,匚wC会安全L中的q字W号Ӟ它的前面要加上一个{义字W“\”?br /><br />图一Q匹配所?23-12-1234形式的社会安全号?br /><br />假设q行搜烦的时候,你希望连字符号可以出玎ͼ也可以不出现——即Q?99-99-9999?99999999都属于正的格式。这Ӟ你可以在q字W号后面加上“?”数量限定符P如图二所C:<br /><br />图二Q匹配所?23-12-1234?23121234形式的社会安全号?br /><br />下面我们再来看另外一个例子。美国汽车牌照的一U格式是四个数字加上二个字母。它的正则表辑ּ前面是数字部分“[0-9]”,再加上字母部分“[A-Z]”。图三显CZ完整的正则表辑ּ?br /><br /><br />图三Q匹配典型的国汽R牌照LQ如8836KV<br /><br /><strong>1.5 “否”符?/strong><br />“^”符L为“否”符受如果用在方括号内,“^”表CZ惌匚w的字W。例如,囑֛的正则表辑ּ匚w所有单词,但以“X”字母开头的单词除外?br /><br />囑֛Q匹配所有单词,但“X”开头的除外<br /><br /><strong>1.6 圆括号和I白W号</strong><br />假设要从格式为“June 26, 1951”的生日日期中提取出月䆾部分Q用来匹配该日期的正则表辑ּ可以如图五所C:<br /><br />五:匚w所有Moth DD,YYYY格式的日?br /><br />新出现的“\s”符hI白W号Q匹配所有的I白字符Q包括Tab字符。如果字W串正确匚wQ接下来如何提取出月份部分呢Q只需在月份周围加上一个圆括号创徏一个组Q然后用ORO APIQ本文后面详l讨论)提取出它的倹{修改后的正则表辑ּ如图六所C:<br /><br /><br />囑օQ匹配所有Month DD,YYYY格式的日期,定义月䆾gؓW一个组<br /><br /><strong>1.7 其它W号</strong><br />为简便v见,你可以用一些ؓ常见正则表达式创建的快捷W号。如表二所C:<br />表二Q常用符?br /><br /><br />例如Q在前面C会安全L的例子中Q所有出现“[0-9]”的地方我们都可以用“\d”。修改后的正则表辑ּ如图七所C?br /><br />图七Q匹配所?23-12-1234格式的社会安全号?br /><br />二、Jakarta-ORO?br />有许多源代码开攄正则表达式库可供JavaE序员用,而且它们中的许多支持Perl 5兼容的正则表辑ּ语法。我在这里选用的是Jakarta-ORO正则表达式库Q它是最全面的正则表辑ּAPI之一Q而且它与Perl 5正则表达式完全兼宏V另外,它也是优化得最好的API之一?br />Jakarta-ORO库以前叫做OROMatcherQDaniel Savarese大方地把它赠送给了Jakarta Project。你可以按照本文最后参考资源的说明下蝲它?br />我首先将要介l用Jakarta-ORO库时你必d建和讉K的对象,然后介绍如何使用Jakarta-ORO API?br />?PatternCompiler对象<br />首先Q创Z个Perl5Compilercȝ实例Qƈ把它赋值给PatternCompiler接口对象。Perl5Compiler是PatternCompiler接口的一个实玎ͼ允许你把正则表达式编译成用来匚w的Pattern对象?br /><br />?Pattern对象<br />要把正则表达式编译成Pattern对象Q调用compiler对象的compile()ҎQƈ在调用参C指定正则表达式。例如,你可以按照下面这U方式编译正则表辑ּ“t[aeio]n”:<br /><br /><br />默认情况下,~译器创Z个大写敏感的模式(patternQ。因此,上面代码~译得到的模式只匚w“tin”、“tan”?“ten”和“ton”,但不匚w“Tin”和“taN”。要创徏一个大写不敏感的模式Q你应该在调用编译器的时候指定一个额外的参数Q?br /><br /><br />创徏好Pattern对象之后Q你可以通过PatternMatchercȝ该Pattern对象q行模式匚w?br />?PatternMatcher对象<br />PatternMatcher对象ҎPattern对象和字W串q行匚w查。你要实例化一个Perl5Matchercdƈ把结果赋值给PatternMatcher接口。Perl5MatchercLPatternMatcher接口的一个实玎ͼ它根据Perl 5正则表达式语法进行模式匹配:<br /><br />使用PatternMatcher对象Q你可以用多个方法进行匹配操作,q些Ҏ的第一个参数都是需要根据正则表辑ּq行匚w的字W串Q?br />boolean matches(String input, Pattern pattern)Q当输入字符串和正则表达式要_匚w时用。换句话_正则表达式必d整地描述输入字符丌Ӏ?br />boolean matchesPrefix(String input, Pattern pattern)Q当正则表达式匹配输入字W串起始部分时用?br />boolean contains(String input, Pattern pattern)Q当正则表达式要匚w输入字符串的一部分时用(卻I它必L一个子Ԍ?br />另外Q在上面三个Ҏ调用中,你还可以用PatternMatcherInput对象作ؓ参数替代String对象Q这Ӟ你可以从字符串中最后一ơ匹配的位置开始l进行匹配。当字符串可能有多个子串匚wl定的正则表辑ּӞ用PatternMatcherInput对象作ؓ参数很有用了。用PatternMatcherInput对象作ؓ参数替代StringӞ上述三个Ҏ的语法如下:<br />boolean matches(PatternMatcherInput input, Pattern pattern)<br />boolean matchesPrefix(PatternMatcherInput input, Pattern pattern)<br />boolean contains(PatternMatcherInput input, Pattern pattern)<br />三、应用实?br />下面我们来看看Jakarta-ORO库的一些应用实例?br /><strong>3.1 日志文g处理</strong><br />dQ分析一个Web服务器日志文Ӟ定每一个用戯在网站上的时间。在典型的BEA WebLogic日志文g中,日志记录的格式如下:<br /><br />分析q个日志记录Q可以发玎ͼ要从q个日志文g提取的内Ҏ两项QIP地址和页面访问时间。你可以用分l符P圆括P从日志记录提取出IP地址和时间标记?br />首先我们来看看IP地址。IP地址?个字节构成,每一个字节的值在0?55之间Q各个字节通过一个句点分隔。因此,IP地址中的每一个字节有臛_一个、最多三个数字。图八显CZ为IP地址~写的正则表辑ּQ?br /><br />囑օQ匹配IP地址<br /><br />IP地址中的句点字符必须q行转义处理Q前面加上“\”)Q因为IP地址中的句点h它本来的含义Q而不是采用正则表辑ּ语法中的Ҏ含义。句点在正则表达式中的特D含义本文前面已l介l?br />日志记录的时间部分由一Ҏ括号包围。你可以按照如下思\提取出方括号里面的所有内容:首先搜烦起始Ҏ号字W(“[”)Q提取出所有不过l束Ҏ号字W(“]”)的内容,向前L直至扑ֈl束Ҏ号字W。图九显CZq部分的正则表达式?br /><br /><br />图九Q匹配至一个字W,直至扑ֈ“]?br /><br />现在Q把上述两个正则表达式加上分l符P圆括P后合q成单个表达式,q样可以从日志记录提取出IP地址和时间。注意,Z匚w? -”(但不提取它)Q正则表辑ּ中间加入了“\s-\s-\s”。完整的正则表达式如囑֍所C?br /><br />囑֍Q匹配IP地址和时间标?br /><br />现在正则表达式已l编写完毕,接下来可以编写用正则表辑ּ库的Java代码了?br />Z用Jakarta-ORO库,首先创徏正则表达式字W串和待分析的日志记录字W串Q?br /><br />q里使用的正则表辑ּ与图十的正则表达式差不多完全相同Q但有一点例外:在Java中,你必d每一个向前的斜杠Q“\”)q行转义处理。图十不是Java的表CŞ式,所以我们要在每个“\”前面加上一个“\”以免出现编译错误。遗憄是,转义处理q程很容易出现错误,所以应该小心}慎。你可以首先输入未经转义处理的正则表辑ּQ然后从左到右依ơ把每一个“\”替换成“\”。如果要复检Q你可以试着把它输出到屏q上?br />初始化字W串之后Q实例化PatternCompiler对象Q用PatternCompiler~译正则表达式创Z个Pattern对象Q?br /><br />现在Q创建PatternMatcher对象Q调用PatternMatcher接口的contain()Ҏ查匹配情况:<br /><br />下来Q利用PatternMatcher接口q回的MatchResult对象Q输出匹配的l。由于logEntry字符串包含匹配的内容Q你可以看到cd下面的输出:<br /><br /><strong>3.2 HTML处理实例一</strong><br />下面一个Q务是分析HTML面内FONT标记的所有属性。HTML面内典型的FONT标记如下所C:<br /><br />E序按照如下Ş式,输出每一个FONT标记的属性:<br /><br />在这U情况下Q我你用两个正则表辑ּ。第一个如囑֍一所C,它从字体标记提取出?face="Arial, Serif" size="+2" color="red"”?br /><br />囑֍一Q匹配FONT标记的所有属?br /><br />W二个正则表辑ּ如图十二所C,它把各个属性分割成名字-值对?br /><br />囑֍二:匚w单个属性,q把它分割成名字-值对<br /><br />分割l果为:<br /><br />现在我们来看看完成这个Q务的Java代码。首先创Z个正则表辑ּ字符Ԍ用Perl5Compiler把它们编译成Pattern对象。编译正则表辑ּ的时候,指定Perl5Compiler.CASE_INSENSITIVE_MASK选项Q得匹配操作不区分大小写?br />接下来,创徏一个执行匹配操作的Perl5Matcher对象<br /><br />假设有一个Stringcd的变量htmlQ它代表了HTML文g中的一行内宏V如果html字符串包含FONT标记Q匹配器返回true。此Ӟ你可以用匚w器对象返回的MatchResult对象获得W一个组Q它包含了FONT的所有属性:<br /><br />接下来创Z个PatternMatcherInput对象。这个对象允怽从最后一ơ匹配的位置开始l进行匹配操作,因此Q它很适合于提取FONT标记内属性的名字-值对。创建PatternMatcherInput对象Q以参数形式传入待匹配的字符丌Ӏ然后,用匹配器实例提取出每一个FONT的属性。这通过指定PatternMatcherInput对象Q而不是字W串对象Qؓ参数Q反复地调用PatternMatcher对象的contains()Ҏ完成。PatternMatcherInput对象之中的每一ơP代将把它内部的指针向前移动,下一ơ检将从前一ơ匹配位|的后面开始?br />本例的输出结果如下:<br /><br /><strong>3.3 HTML处理实例?/strong><br />下面我们来看看另一个处理HTML的例子。这一ơ,我们假定Web服务器从widgets.acme.comUd了newserver.acme.com。现在你要修改一些页面中的链接:<br /><br />执行q个搜烦的正则表辑ּ如图十三所C:<br /><br />囑֍三:匚w修改前的链接<br /><br />如果能够匚wq个正则表达式,你可以用下面的内Ҏ换图十三的链接:<br /><br />注意#字符的后面加上了。Perl正则表达式语法用、等表示已经匚w且提取出来的l。图十三的表辑ּ把所有作Z个组匚w和提取出来的内容附加到链接的后面?br />现在Q返回Java。就象前面我们所做的那样Q你必须创徏试字符Ԍ创徏把正则表辑ּ~译到Pattern对象所必需的对象,以及创徏一个PatternMatcher?br /><br />接下来,用com.oroinc.text.regex包Utilcȝsubstitute()静态方法进行替换,输出l果字符Ԍ<br /><br />Util.substitute()Ҏ的语法如下:<br /><br />q个调用的前两个参数是以前创建的PatternMatcher和Pattern对象。第三个参数是一个Substiution对象Q它军_了替换操作如何进行。本例用的是Perl5Substitution对象Q它能够q行Perl5风格的替换。第四个参数是想要进行替换操作的字符Ԍ最后一个参数允许指定是否替换模式的所有匹配子ԌUtil.SUBSTITUTE_ALLQ,或只替换指定的次数?br />【结束语】在q篇文章中,我ؓ你介l了正则表达式的强大功能。只要正运用,正则表达式能够在字符串提取和文本修改中v到很大的作用。另外,我还介绍了如何在JavaE序中通过Jakarta-ORO库利用正则表辑ּ。至于最l采用老式的字W串处理方式Q用StringTokenizerQcharAtQ和substringQ,q是采用正则表达式,q就有待你自己决定了?/p> </td> </tr> </tbody> </table> <img src ="http://www.aygfsteel.com/mlw2000/aggbug/71700.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/mlw2000/" target="_blank">mlw2000</a> 2006-09-25 11:53 <a href="http://www.aygfsteel.com/mlw2000/articles/71700.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>怎样创徏和用日?/title><link>http://www.aygfsteel.com/mlw2000/articles/71691.html</link><dc:creator>mlw2000</dc:creator><author>mlw2000</author><pubDate>Mon, 25 Sep 2006 03:30:00 GMT</pubDate><guid>http://www.aygfsteel.com/mlw2000/articles/71691.html</guid><wfw:comment>http://www.aygfsteel.com/mlw2000/comments/71691.html</wfw:comment><comments>http://www.aygfsteel.com/mlw2000/articles/71691.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/mlw2000/comments/commentRss/71691.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/mlw2000/services/trackbacks/71691.html</trackback:ping><description><![CDATA[ <h4 class="TextColor1" id="subjcns!3C3DD8BEC2AFC122!122" style="MARGIN-BOTTOM: 0px"> <strong> <font face="宋体" size="5">计算Java日期</font> </strong> <br />学习怎样创徏和用日?<br /><strong>概要</strong><br />    不管你是处理财务交易q是计划着下一步的行动Q你都要知道怎样在Java中徏立,使用和显C日期。这需要你单的查阅一下相应类的API参考:一个日期可以创?个相关类的对象。这文章告诉你你想要知道的内容。(3,000字)<br /><strong>作者:</strong>Robert Nielsen <br /><strong>译Q?/strong>Cocia Lin</h4> <div class="wmqeeuq" id="msgcns!3C3DD8BEC2AFC122!122"> <div> <p>    Javal计?970q??日v的毫U的数量表示日期。也是_例如Q?970q??日,是在1?日后?6Q?00Q?00毫秒。同LQ?969q?2?1日是?970q??日前86Q?00Q?00毫秒。Java的DatecM用longcdU录q些毫秒?因ؓlong是有W号整数Q所以日期可以在1970q??日之前,也可以在q之后。Longcd表示的最大正值和最大负值可以轻杄表示290Q?00Q?00q的旉Q这适合大多Ch的时间要求?br /><strong>Date c?br />   </strong>Datecd以在java.util包中扑ֈQ用一个longcd的DCZ个指定的时刻。它的一个有用的构造函数是Date(),它创Z个表C创建时ȝ对象。getTime()Ҏq回Date对象的long倹{在下面的程序中Q我使用Date()构造函数创Z个表C程序运行时ȝ对象Qƈ且利用getTime()Ҏ扑ֈq个日期代表的毫U数量:</p> <p>import java.util.*;</p> <p> <br />public class Now {<br />   public static void main(String[] args) {<br />      Date now = new Date();<br />      long nowLong = now.getTime();<br />      System.out.println("Value is " + nowLong);<br />   }<br />}<br /><br />当我q行q个E序后,我得?72,568,255,150.快速确认一下这个数字,L在一个合理的范围Q它不到31q_q个数值相?970q??日到我写q篇文章的时间来_是合理的。计机是这个毫UDC时_Z可不愿意? 我将?96,321,998,34见到你?q运的是QJava提供了一个{换Date对象到字W串的途径Q表C成传统的Ş式。我们在下一节讨论DateFormatc,它直观的建立日期字符丌Ӏ?<br />DateFormatc?br /> DateFormatcȝ一个目标是建立一个h们能够识别的字符丌Ӏ然而,因ؓ语言的差别,不是所有的人希望看C格的相同格式的日期。法国h更喜Ƣ看?25 decembre 2000,",但是国Z惯看?December 25,2000."所以一个DateFormat的实例创Z后,q个对象包含了日期的昄格式的信息。如果用用L脑区域设|缺省的格式Q你可以象下面那P创徏DateFormat对象Q用getDateInstance()ҎQ?/p> <p>DateFormat df = DateFormat.getDateInstance();   <br /><br />DateFormatcdjava.text包中可以扑ֈ?br /><strong>转换成字W串<br /></strong>你可以用format()Ҏ转换Date对象Z个字W串。下面的CZE序说明了这个问题:</p> <p>import java.util.*;<br />import java.text.*;</p> <p>public class NowString {<br />   public static void main(String[] args) {<br />      Date now = new Date();<br />      DateFormat df = DateFormat.getDateInstance();<br />      String s = df.format(now);<br />      System.out.println("Today is " + s);<br />   }<br />}  <br /><br />在上面的代码中,展示了没有参敎ͼ使用~省格式的getDateInstance()Ҏ。Javaq提供了几个选择日期格式Q你可以通过使用重蝲的getDateInstance(int style)获得。出于方便的原因QDateFormat提供了几U预|的帔RQ你可以使用q些帔R参数。下面是几个SHORT, MEDIUM, LONG, 和FULLcd的示例:</p> <p>import java.util.*;<br />import java.text.*;</p> <p>public class StyleDemo {<br />   public static void main(String[] args) {<br />      Date now = new Date();</p> <p>      DateFormat df =  DateFormat.getDateInstance();<br />      DateFormat df1 = DateFormat.getDateInstance(DateFormat.SHORT);<br />      DateFormat df2 = DateFormat.getDateInstance(DateFormat.MEDIUM);<br />      DateFormat df3 = DateFormat.getDateInstance(DateFormat.LONG);<br />      DateFormat df4 = DateFormat.getDateInstance(DateFormat.FULL); <br />      String s =  df.format(now);<br />      String s1 = df1.format(now);<br />      String s2 = df2.format(now);<br />      String s3 = df3.format(now);<br />      String s4 = df4.format(now);</p> <p>      System.out.println("(Default) Today is " + s);<br />      System.out.println("(SHORT)   Today is " + s1);<br />      System.out.println("(MEDIUM)  Today is " + s2);<br />      System.out.println("(LONG)    Today is " + s3);<br />      System.out.println("(FULL)    Today is " + s4);<br />   }<br />}<br /><br />E序输出如下Q?/p> <p>(Default) Today is Nov 8, 2000<br />(SHORT)   Today is 11/8/00<br />(MEDIUM)  Today is Nov 8, 2000<br />(LONG)    Today is November 8, 2000<br />(FULL)    Today is Wednesday, November 8, 2000<br /><br />同样的程序,在我的电脑上使用~省讄q行后,改变区域讄为瑞典,输出如下Q?/p> <p>(Default) Today is 2000-nov-08<br />(SHORT)   Today is 2000-11-08<br />(MEDIUM)  Today is 2000-nov-08<br />(LONG)    Today is den 8 november 2000<br />(FULL)    Today is den 8 november 2000     <br />  <br />从这里,你能看到Q瑞典的月䆾不是大写的(虽然Novemberq是novemberQ?q有QLONG和FULL版本在瑞典语中是一LQ但是美国英语却不同。另外,有趣的是Q瑞典语单词的星期三,onsdagQ没有包含在FULL日期里,p却包括?<br />注意你能够用getDateInstance()Ҏ改变DateFormat实例的语U;但是Q在上面的例子中Q是通过改变Windows98的控刉板的区域讄做到的。不同的地方的区域设|不同,l果׃同,q样有好处,也有不QJavaE序员应该了解这些。一个好处是JavaE序员可以只写一行代码就可以昄日期Q而且世界不同地区的电脑运行同LE序会有不用的日期格式?但是q也是一个缺点,当程序员希望昄同一U格式的?-q也有可取之处,举例来说Q在E序中؜合输出文本和日期Q如果文本是英文Q我们就不希望日期格式是其他的格式,象d文或是西班牙文。如果程序员依靠日期格式~程Q日期格式将Ҏq行E序所在电脑的区域讄不用而不同?<br /><font size="4"><strong>解析字符?/strong></font><br /> 通过parse()ҎQDateFormat能够以一个字W串创立一个Date对象。这个方法能抛出ParseException异常Q所以你必须使用适当的异常处理技术。下面的例子E序通过字符串创建Date对象Q?/p> <p>import java.util.*;<br />import java.text.*;</p> <p>public class ParseExample {<br />   public static void main(String[] args) {<br />      String ds = "November 1, 2000";<br />      DateFormat df = DateFormat.getDateInstance();<br />      try {<br />         Date d = df.parse(ds);<br />      }<br />      catch(ParseException e) {<br />         System.out.println("Unable to parse " + ds);<br />      }<br />   }<br />}<br /><br />在创Z个Q意的日期时parse()Ҏ很有用。我通过另一U方法创Z个Q意得日期。同Ӟ你将看到怎样q行基本日期计算Q例如计?0天后的另一天。你可以使用GregorianCalendarcL完成q个d?<br /><strong>GregorianCalendarc?/strong><br /> 创徏一个代表Q意日期的一个途径使用GregorianCalendarcȝ构造函敎ͼ它包含在java.util包中Q?/p> <p>GregorianCalendar(int year, int month, int date) <br /><br />注意月䆾的表C,一月是0Q二月是1Q以此类推,?2月是11。因为大多数Z惯于使用单词而不是用数字来表示月䆾Q这L序也许更易读Q父cCalendar使用帔R来表C月份:JANUARY, FEBRUARY,{等。所以,创徏Wilbur ?Orville刉第一架动力飞机的日期QDecember 17, 1903Q,你可以用:</p> <p>GregorianCalendar firstFlight = new GregorianCalendar(1903, Calendar.DECEMBER, 17);  <br />Z清楚的考虑Q你应该使用前面的Ş式。但是,你也应该学习怎样阅读下面的短格式。下面的例子同样表示December 17,1903Q记住,在短格式中,11表示DecemberQ?/p> <p>GregorianCalendar firstFlight = new GregorianCalendar(1903, 11, 17);   <br /><br />在上一节中Q你学习了{换Date对象到字W串。这里,你可以做同样的事情;但是首先Q你需要将GregorianCalendar对象转换到Date。要做到q一点,你可以用getTime()ҎQ从它得父类Calendarl承而来。GetTime()Ҏq回GregorianCalendar相应的Date对象。你能够创徏GregorianCalendar对象Q{换到Date对象Q得到和输出相应的字W串q样一个过E。下面是例子Q?</p> <p>import java.util.*;<br />import java.text.*;</p> <p>public class Flight {</p> <p>   public static void main(String[] args) {<br />      GregorianCalendar firstFlight = new GregorianCalendar(1903, Calendar.DECEMBER, 17);    <br />      Date d = firstFlight.getTime();<br />      DateFormat df = DateFormat.getDateInstance();<br />      String s = df.format(d);<br />      System.out.println("First flight was " + s);<br />   }<br />}<br /><br />有时候创Z个代表当前时ȝGregorianCalendarcȝ实例是很有用的。你可以单的使用没有参数的GregorianCalendar构造函敎ͼ象这P</p> <p>GregorianCalendar thisday = new GregorianCalendar();<br /><br />一个输Z天日期的例子E序Q用GregorianCalendar对象Q?/p> <p>import java.util.*;<br />import java.text.*;</p> <p>class Today {<br />   public static void main(String[] args) {<br />      GregorianCalendar thisday = new GregorianCalendar(); <br />      Date d = thisday.getTime();<br />      DateFormat df = DateFormat.getDateInstance();<br />      String s = df.format(d);<br />      System.out.println("Today is " + s);<br />   }<br />}<br /><br />注意刎ͼDate()构造函数和GregorianCalendar()构造函数很cMQ都创徏一个对象,条g单,代表今天?br /><strong>日期处理<br /></strong>GregorianCalendarcL供处理日期的Ҏ。一个有用的Ҏ是add().使用add()ҎQ你能够增加象年Q月敎ͼ天数到日期对象中。要使用add()ҎQ你必须提供要增加的字段Q要增加的数量。一些有用的字段是DATE, MONTH, YEAR, ?WEEK_OF_YEAR。下面的E序使用add()Ҏ计算未来80天的一个日期。在Jules?lt;环球80?gt;是一个重要的数字Q用这个程序可以计Phileas Fogg从出发的那一?872q?0?日后80天的日期Q?/p> <p>import java.util.*;<br />import java.text.*;</p> <p>public class World {<br />   public static void main(String[] args) {<br />      GregorianCalendar worldTour = new GregorianCalendar(1872, Calendar.OCTOBER, 2);<br />      worldTour.add(GregorianCalendar.DATE, 80);<br />      Date d = worldTour.getTime();<br />      DateFormat df = DateFormat.getDateInstance();<br />      String s = df.format(d);<br />      System.out.println("80 day trip will end " + s);<br />   }<br />}<br /><br />q个例子是想象的Q但在一个日期上增加天数是一个普遍的操作Q媄可以租3天,图书馆可以借书21天,商店l常需要将购买的物品在30天内卖出。下面的E序演示了用年计算Q?/p> <p>import java.util.*;<br />import java.text.*;</p> <p>public class Mortgage {<br />   public static void main(String[] args) {<br />      GregorianCalendar mortgage = new GregorianCalendar(1997, Calendar.MAY, 18);<br />      mortgage.add(Calendar.YEAR, 15);<br />      Date d = mortgage.getTime();<br />      DateFormat df = DateFormat.getDateInstance();<br />      String s = df.format(d);<br />      System.out.println("15 year mortgage amortized on " + s);    }<br />}<br /><br />    add()一个重要的副作用是它改变的原来的日期。有时候,拥有原始日期和修改后的日期很重要。不q的是,你不能简单的创徏一个GregorianCalendar对象Q设|它和原来的相等QequalQ。原因是两个变量指向同一个Date()对象地址。如果Date对象改变Q两个变量就指向改变后的日期对象。代替这U做法,应该创徏一个新对象。下面的E序C了这U做法:</p> <p>import java.util.*;<br />import java.text.*;</p> <p>public class ThreeDates {<br />   public static void main(String[] args) {<br />      GregorianCalendar gc1 = new GregorianCalendar(2000, Calendar.JANUARY, 1);<br />      GregorianCalendar gc2 = gc1;<br />      GregorianCalendar gc3 = new GregorianCalendar(2000, Calendar.JANUARY, 1);<br />      //Three dates all equal to January 1, 2000</p> <p>      gc1.add(Calendar.YEAR, 1);<br />      <a><u><font color="#0000ff">file://gc1</font></u></a> and gc2 are changed</p> <p>      DateFormat df = DateFormat.getDateInstance();</p> <p>      Date d1 = gc1.getTime();<br />      Date d2 = gc2.getTime();<br />      Date d3 = gc3.getTime();</p> <p>      String s1 = df.format(d1);<br />      String s2 = df.format(d2);<br />      String s3 = df.format(d3);</p> <p>      System.out.println("gc1 is " + s1);<br />      System.out.println("gc2 is " + s2);<br />      System.out.println("gc3 is " + s3);<br />   }<br />}<br /><br />    E序q行后,gc1和gc2被变?001q_因ؓ两个对象指向同一个DateQ而Date已经被改变了Q。对象gc3指向一个单独的DateQ它没有被改变?br />计算复习日期<br />在这节,你将看到一个依据现实世界的例子。这个详l的E序计算q去一个具体的日期。例如,你阅读这文章,你想要记住一个印象深ȝ知识炏V如果你没有照片一L记忆力,你就要定期的复习q些新资料,q将帮助你记住它。关于复习系l,Kurt Hanks ?Gerreld L. Pulsipher在他们的< Five Secrets to Personal Productivity个h能力?个秘?gt;中有讨论Q徏议看q第一眼后马上回顾一下,然后?天后Q?个星期后Q?个月后,3个月后,1q后。我的这文章,你要马上回顾一下,从现在算P再就是明天,然后?个星期,1个月Q?个月Q?q后。我们的E序计这些日期?br />q个E序非常有用的,它将是PIM(Personal Information Manager个h信息理?的一个组成部分,q将定复习旉。在下面的程序中QgetDates()Ҏ对一个返回日期数l(复习日期Q的电子软g很有用。另外,你可以返回单独的一个日期,使用getFirstDay(),getOneDay(),getOneWeek(),getOnMonth()和getOneYear().当时间范围超个PIM的ReviewDates的计范围时ReviewDatescLCZ怎样计算旉Dc现在,你可以容易的修改它用来处理你需要的旉D,象图书馆借书Q录影带U赁和抵D。首先,ReviewDatescLC在下面Q?/p> <p>import java.util.*;<br />import java.text.*;</p> <p>public class ReviewDates {<br />   private GregorianCalendar firstDay, oneDay, oneWeek, oneMonth, oneQuarter, oneYear;<br />   final int dateArraySize = 6;</p> <p>   ReviewDates(GregorianCalendar gcDate) {<br />      int year = gcDate.get(GregorianCalendar.YEAR);<br />      int month = gcDate.get(GregorianCalendar.MONTH);<br />      int date = gcDate.get(GregorianCalendar.DATE);</p> <p>      firstDay = new GregorianCalendar(year, month, date);<br />      oneDay = new GregorianCalendar(year, month, date);<br />      oneWeek = new GregorianCalendar(year, month, date);<br />      oneMonth = new GregorianCalendar(year, month, date);<br />      oneQuarter = new GregorianCalendar(year, month, date);<br />      oneYear = new GregorianCalendar(year, month, date);</p> <p>      oneDay.add(GregorianCalendar.DATE, 1);<br />      oneWeek.add(GregorianCalendar.DATE, 7);<br />      oneMonth.add(GregorianCalendar.MONTH, 1);<br />      oneQuarter.add(GregorianCalendar.MONTH, 3);<br />      oneYear.add(GregorianCalendar.YEAR, 1);<br />   }</p> <p>   ReviewDates() {<br />      this(new GregorianCalendar());<br />   }</p> <p>   public void listDates() {<br />      DateFormat df = DateFormat.getDateInstance(DateFormat.LONG); <br />      Date startDate = firstDay.getTime();<br />      Date date1 = oneDay.getTime();<br />      Date date2 = oneWeek.getTime();<br />      Date date3 = oneMonth.getTime();<br />      Date date4 = oneQuarter.getTime();<br />      Date date5 = oneYear.getTime();</p> <p>      String ss =  df.format(startDate);<br />      String ss1 = df.format(date1);<br />      String ss2 = df.format(date2);<br />      String ss3 = df.format(date3);<br />      String ss4 = df.format(date4);<br />      String ss5 = df.format(date5);</p> <p>      System.out.println("Start date is " + ss);<br />      System.out.println("Following review dates are:");<br />      System.out.println(ss1);<br />      System.out.println(ss2);<br />      System.out.println(ss3);<br />      System.out.println(ss4);<br />      System.out.println(ss5);<br />      System.out.println();<br />   }</p> <p>   public GregorianCalendar[] getDates() {<br />      GregorianCalendar[] memoryDates = new GregorianCalendar[dateArraySize];<br />      memoryDates[0] = firstDay;<br />      memoryDates[1] = oneDay;<br />      memoryDates[2] = oneWeek;<br />      memoryDates[3] = oneMonth;<br />      memoryDates[4] = oneQuarter;<br />      memoryDates[5] = oneYear;<br />      return memoryDates;<br />   }</p> <p>   public GregorianCalendar getFirstDay() {<br />      return this.firstDay;<br />   }</p> <p>   public GregorianCalendar getOneDay() {<br />      return this.oneDay;<br />   }</p> <p>   public GregorianCalendar getOneWeek() {<br />      return this.oneWeek;<br />   }</p> <p>   public GregorianCalendar getOneMonth() {<br />      return this.oneMonth;<br />   }</p> <p>   public GregorianCalendar getOneQuarter() {<br />      return this.oneQuarter;<br />   }</p> <p>   public GregorianCalendar getOneYear() {<br />      return this.oneYear;<br />   }<br />} <br /><br />下面是用ReviewDatescd出复习日期的例子E序Q?/p> <p>import java.util.*;</p> <p>public class ShowDates {<br />   public static void main(String[] args) {<br />      ReviewDates rd = new ReviewDates();<br />      rd.listDates();</p> <p>      GregorianCalendar gc = new GregorianCalendar(2001, Calendar.JANUARY, 15);<br />      ReviewDates jan15 = new ReviewDates(gc);<br />      jan15.listDates();<br />   }<br />}<br /><br /><strong>ȝ</strong><br /> q篇文章介绍了关于日期处理的3个重要的c:Date,DateFormat,GregorianCalendar.q些c让你创建日期,转换成字W串Q和计算日期基本元素。处理Java中的日期问题Q这文章只是冰׃角。可是,我在q里介绍的类和方法不仅仅是你学习高技术的xQ这些类和方法本w就可以处理很多通常的日期相关的d<br /></p> </div> </div> <img src ="http://www.aygfsteel.com/mlw2000/aggbug/71691.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/mlw2000/" target="_blank">mlw2000</a> 2006-09-25 11:30 <a href="http://www.aygfsteel.com/mlw2000/articles/71691.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java中一些关于日期、日期格式、日期的解析和日期的计算[转脓]http://www.aygfsteel.com/mlw2000/articles/71689.htmlmlw2000mlw2000Mon, 25 Sep 2006 03:27:00 GMThttp://www.aygfsteel.com/mlw2000/articles/71689.htmlhttp://www.aygfsteel.com/mlw2000/comments/71689.htmlhttp://www.aygfsteel.com/mlw2000/articles/71689.html#Feedback0http://www.aygfsteel.com/mlw2000/comments/commentRss/71689.htmlhttp://www.aygfsteel.com/mlw2000/services/trackbacks/71689.html

Java中一些关于日期、日期格式、日期的解析和日期的计算[转脓]

sunmoon | 2005q?4?1? 11:45

Java中一些关于日期、日期格式、日期的解析和日期的计算

Java 语言的Calendar(日历),Date(日期), 和DateFormat(日期格式)l成了Java标准的一个基本但是非帔R要的部分. 日期是商业逻辑计算一个关键的部分. 所有的开发者都应该能够计算未来的日? 定制日期的显C格? q将文本数据解析成日期对? 我们写了两篇文章, q是W一? 我们大概的学习日期, 日期格式, 日期的解析和日期的计?

我们讨Z面的c?

1、具体类(和抽象类相对)java.util.Date
2、抽象类java.text.DateFormat 和它的一个具体子c?java.text.SimpleDateFormat
3、抽象类java.util.Calendar 和它的一个具体子c?java.util.GregorianCalendar

具体cd以被实例? 但是抽象cd不能. 你首先必d现抽象类的一个具体子c?

Date cMJava 开发包(JDK) 1.0 开始进? 当时它只包含了几个取得或者设|一个日期数据的各个部分的方? 比如说月, ? 和年. q些Ҏ现在遭到了批评ƈ且已l被转移CCalendarc里M, 我们在本文中进一步讨论它. q种改进旨在更好的处理日期数据的国际化格? p在JDK 1.1中一? Date cd际上只是一个包裹类, 它包含的是一个长整型数据, 表示的是从GMT(格林治标准旉)1970q? 1 ?1?0:00:00q一M前或者是之后l历的毫U数.

一、创Z个日期对?

让我们看一个用系l的当前日期和时间创Z个日期对象ƈq回一个长整数的简单例? q个旉通常被称为Java 虚拟?JVM)L环境的系l时?
//------------------------------------------------------
import java.util.Date;

public class DateExample1
{
public static void main(String[] args)
{
// Get the system date/time
Date date = new Date();

System.out.println(date.getTime());
}
}
//------------------------------------------------------

在星期六, 2001q??9? 下午大约?:50的样? 上面的例子在pȝ输出讑֤上显C的l果?1001803809710. 在这个例子中,值得注意的是我们使用了Date 构造函数创Z个日期对? q个构造函数没有接受Q何参? 而这个构造函数在内部使用了System.currentTimeMillis() Ҏ来从pȝ获取日期.

那么, 现在我们已经知道了如何获取从1970q??日开始经历的毫秒C. 我们如何才能以一U用h白的格式来显C个日期呢? 在这里类java.text.SimpleDateFormat 和它的抽象基c?java.text.DateFormat 派得上用场?

二、日期数据的定制格式

假如我们希望定制日期数据的格? 比方星期?9?29?2001q? 下面的例子展CZ如何完成q个工作:

//------------------------------------------------------
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateExample2
{

public static void main(String[] args)
{

SimpleDateFormat bartDateFormat =
new SimpleDateFormat("EEEE-MMMM-dd-yyyy");

Date date = new Date();

System.out.println(bartDateFormat.format(date));
}
}
//------------------------------------------------------

只要通过向SimpleDateFormat 的构造函C递格式字W串"EEE-MMMM-dd-yyyy", 我们p够指明自己想要的格式. 你应该可以看? 格式字符串中的ASCII 字符告诉格式化函C面显C日期数据的哪一个部? EEEE是星? MMMM是月, dd是日, yyyy是年. 字符的个数决定了日期是如何格式化?传?EE-MM-dd-yy"会显C?Sat-09-29-01. 请察看Sun 公司的Web 站点获取日期格式化选项的完整的指示.

三、将文本数据解析成日期对?

假设我们有一个文本字W串包含了一个格式化了的日期对象, 而我们希望解析这个字W串q从文本日期数据创徏一个日期对? 我们再ơ以格式化字W串"MM-dd-yyyy" 调用SimpleDateFormatc? 但是q一? 我们使用格式化解析而不是生成一个文本日期数? 我们的例? 昄在下? 解析文本字W串"9-29-2001"q创Z个gؓ001736000000 的日期对?

//------------------------------------------------------
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateExample3
{

public static void main(String[] args)
{
// Create a date formatter that can parse dates of
// the form MM-dd-yyyy.
SimpleDateFormat bartDateFormat =
new SimpleDateFormat("MM-dd-yyyy");

// Create a string containing a text date to be parsed.
String dateStringToParse = "9-29-2001";

try {
// Parse the text version of the date.
// We have to perform the parse method in a
// try-catch construct in case dateStringToParse
// does not contain a date in the format we are expecting.
Date date = bartDateFormat.parse(dateStringToParse);

// Now send the parsed date as a long value
// to the system output.
System.out.println(date.getTime());
}
catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
}
//------------------------------------------------------

四、用标准的日期格式化过E?

既然我们已经可以生成和解析定制的日期格式? 让我们来看一看如何用内建的格式化过E? Ҏ DateFormat.getDateTimeInstance() 让我们得以用几种不同的方法获得标准的日期格式化过E? 在下面的例子? 我们获取了四个内建的日期格式化过E? 它们包括一个短? 中等? 长的, 和完整的日期格式.

//------------------------------------------------------
import java.text.DateFormat;
import java.util.Date;

public class DateExample4
{

public static void main(String[] args)
{
Date date = new Date();

DateFormat shortDateFormat =
DateFormat.getDateTimeInstance(
DateFormat.SHORT,
DateFormat.SHORT);

DateFormat mediumDateFormat =
DateFormat.getDateTimeInstance(
DateFormat.MEDIUM,
DateFormat.MEDIUM);

DateFormat longDateFormat =
DateFormat.getDateTimeInstance(
DateFormat.LONG,
DateFormat.LONG);

DateFormat fullDateFormat =
DateFormat.getDateTimeInstance(
DateFormat.FULL,
DateFormat.FULL);

System.out.println(shortDateFormat.format(date));
System.out.println(mediumDateFormat.format(date));
System.out.println(longDateFormat.format(date));
System.out.println(fullDateFormat.format(date));
}
}
//------------------------------------------------------

注意我们在对 getDateTimeInstance的每ơ调用中都传递了两个? W一个参数是日期风格, 而第二个参数是时间风? 它们都是基本数据cdint(整型). 考虑到可L? 我们使用了DateFormat cL供的帔R: SHORT, MEDIUM, LONG, ?FULL. 要知道获取时间和日期格式化过E的更多的方法和选项, LSun 公司Web 站点上的解释.

q行我们的例子程序的时? 它将向标准输备输Z面的内容:
9/29/01 8:44 PM
Sep 29, 2001 8:44:45 PM
September 29, 2001 8:44:45 PM EDT
Saturday, September 29, 2001 8:44:45 PM EDT

五、Calendar c?

我们现在已经能够格式化ƈ创徏一个日期对象了, 但是我们如何才能讄和获取日期数据的特定部分? 比如说小? ? 或者分? 我们又如何在日期的这些部分加上或者减d呢? {案是用Calendar c? 如我们前面提到的那? Calendar cM的方法替代了Date cM被hN的方?

假设你想要设|? 获取, 和操U一个日期对象的各个部分, 比方一个月的一天或者是一个星期的一? Z演示q个q程, 我们用具体的子类 java.util.GregorianCalendar. 考虑下面的例? 它计得C面的W十个星期五?3?

//------------------------------------------------------
import java.util.GregorianCalendar;
import java.util.Date;
import java.text.DateFormat;

public class DateExample5
{

public static void main(String[] args)
{
DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.FULL);

// Create our Gregorian Calendar.
GregorianCalendar cal = new GregorianCalendar();

// Set the date and time of our calendar
// to the system&s date and time
cal.setTime(new Date());

System.out.println("System Date: " +
dateFormat.format(cal.getTime()));

// Set the day of week to FRIDAY
cal.set(GregorianCalendar.DAY_OF_WEEK,
GregorianCalendar.FRIDAY);
System.out.println("After Setting Day of Week to Friday: " +
dateFormat.format(cal.getTime()));

int friday13Counter = 0;

while (friday13Counter <= 10)
{

// Go to the next Friday by adding 7 days.
cal.add(GregorianCalendar.DAY_OF_MONTH, 7);

// If the day of month is 13 we have
// another Friday the 13th.
if (cal.get(GregorianCalendar.DAY_OF_MONTH) == 13)
{
friday13Counter++;
System.out.println(dateFormat.format(cal.getTime()));
}
}
}
}
//------------------------------------------------------

在这个例子中我们作了有趣的函数调?
cal.set(GregorianCalendar.DAY_OF_WEEK,
GregorianCalendar.FRIDAY);

?
cal.add(GregorianCalendar.DAY_OF_MONTH, 7);

set Ҏ能够让我们通过单的讄星期中的哪一天这个域来将我们的时间调整ؓ星期? 注意到这里我们用了帔R DAY_OF_WEEK ?FRIDAY来增Z码的可读? add Ҏ让我们能够在日期上加上数? 润年的所有复杂的计算都由q个Ҏ自动处理.

我们q个例子的输出结果是:
System Date: Saturday, September 29, 2001
当我们将它设|成星期五以后就成了: Friday, September 28, 2001
Friday, September 13, 2002
Friday, December 13, 2002
Friday, June 13, 2003
Friday, February 13, 2004
Friday, August 13, 2004
Friday, May 13, 2005
Friday, January 13, 2006
Friday, October 13, 2006
Friday, April 13, 2007
Friday, July 13, 2007
Friday, June 13, 2008

六、时间掌握在你的手里

有了q些Date 和Calendar cȝ例子, 你应该能够?java.util.Date, java.text.SimpleDateFormat, ?java.util.GregorianCalendar 创徏许多Ҏ?



mlw2000 2006-09-25 11:27 发表评论
]]>
字符串{日期或日期{字符??http://www.aygfsteel.com/mlw2000/articles/71679.htmlmlw2000mlw2000Mon, 25 Sep 2006 03:11:00 GMThttp://www.aygfsteel.com/mlw2000/articles/71679.htmlhttp://www.aygfsteel.com/mlw2000/comments/71679.htmlhttp://www.aygfsteel.com/mlw2000/articles/71679.html#Feedback1http://www.aygfsteel.com/mlw2000/comments/commentRss/71679.htmlhttp://www.aygfsteel.com/mlw2000/services/trackbacks/71679.html 有一些网友问我字W串转日期或日期转字W串要如何做Q本来已l在留言板回{了Q但觉得g有满多的|友有这U困扎ͼ因此我把它整理整理脓出来?

鲲鹏|?/a>

鲲鹏|?/a>

在这文章中Q我用的API是SimpleDateFormatQ它是属于java.text.SimpleDateFormatQ所以请记得importq来Q?


用法Q?/font>


SimpleDateFormat sdf  =   new  SimpleDateFormat( " yyyy-MM-dd HH:mm:ss " ); 

q一行最重要Q它立了{换的格式Qyyyy是完整的公元q_MM是月份,dd是日期,至于HH:mm:ss׃需要我再解释了吧!


ps:Z么有的格式大写,有的格式写Q那是怕避免؜淆,例如MM是月份,mm是分QHH?4时Ӟ而hh?2时?



1.字符串{日期Q?

 
2002-10-8 15:30:22要把它{成日期,可以?/font>


Date date = sdf.parse( " 2002-10-8 15:30:22 " );

2.日期转字W串



假如把今天的日期转成字符串可?/font>


String datestr = sdf.format( new  Date()); 

 q个字符串的内容便类?002-10-08 14:55:38


透过q个API我们便可以随心所Ʋ的日期{成我们想要的字符串格式,例如希望日期输出成2002q?0?8?/st1:chsdate>Q?


我们可以q么写:


SimpleDateFormat sdf  =   new  SimpleDateFormat( " yyyyqMM月dd?" );
    String datestr = sdf.format( new  Date()); 


datestr便会依照我们讑֮的格式输?/font>



mlw2000 2006-09-25 11:11 发表评论
]]>
ThreadLocal的设计与使用http://www.aygfsteel.com/mlw2000/articles/65047.htmlmlw2000mlw2000Tue, 22 Aug 2006 04:58:00 GMThttp://www.aygfsteel.com/mlw2000/articles/65047.htmlhttp://www.aygfsteel.com/mlw2000/comments/65047.htmlhttp://www.aygfsteel.com/mlw2000/articles/65047.html#Feedback0http://www.aygfsteel.com/mlw2000/comments/commentRss/65047.htmlhttp://www.aygfsteel.com/mlw2000/services/trackbacks/65047.html
ThreadLocal的设计与使用
来源Q?font color="#669999"> 天极|?  作者: srx81

  早在Java 1.2推出之时QJavaq_中就引入了一个新的支持:java.lang.ThreadLocalQ给我们在编写多U程E序时提供了一U新的选择。用这个工L可以很简z地~写Z的多线E程序,虽然ThreadLocal非常有用Q但是似乎现在了解它、用它的朋友还不多?

  ThreadLocal是什?/p>

  ThreadLocal是什么呢Q其实ThreadLocalq是一个线E的本地实现版本Q它q不是一个ThreadQ而是thread local variableQ线E局部变量)。也许把它命名ؓThreadLocalVar更加合适。线E局部变量(ThreadLocalQ其实的功用非常单,是为每一个用该变量的线E都提供一个变量值的副本Q是每一个线E都可以独立地改变自q副本Q而不会和其它U程的副本冲H。从U程的角度看Q就好像每一个线E都完全拥有该变量。线E局部变量ƈ不是Java的新发明Q在其它的一些语a~译器实玎ͼ如IBM XL FORTRANQ中Q它在语a的层ơ提供了直接的支持。因为Java中没有提供在语言层次的直接支持,而是提供了一个ThreadLocal的类来提供支持,所以,在Java中编写线E局部变量的代码相对比较W拙Q这也许是线E局部变量没有在Java中得到很好的普及的一个原因吧?/p>

  ThreadLocal的设?/p>

  首先看看ThreadLocal的接口:

  Object get() ; // q回当前U程的线E局部变量副?protected Object initialValue(); // q回该线E局部变量的当前U程的初始值void set(Object value); // 讄当前U程的线E局部变量副本的?/p>

  ThreadLocal?个方法,其中值得注意的是initialValue()Q该Ҏ是一个protected的方法,昄是ؓ了子c重写而特意实现的。该Ҏq回当前U程在该U程局部变量的初始|q个Ҏ是一个gq调用方法,在一个线E第1ơ调用get()或者set(Object)时才执行Qƈ且仅执行1ơ。ThreadLocal中的实实现直接q回一个nullQ?/p>

protected Object initialValue() { return null; }

  ThreadLocal是如何做Cؓ每一个线E维护变量的副本的呢Q其实实现的思\很简单,在ThreadLocalcM有一个MapQ用于存储每一个线E的变量的副本。比如下面的CZ实现Q?/p>

public class ThreadLocal
{
 private Map values = Collections.synchronizedMap(new HashMap());
 public Object get()
 {
  Thread curThread = Thread.currentThread();
  Object o = values.get(curThread);
  if (o == null && !values.containsKey(curThread))
  {
   o = initialValue();
   values.put(curThread, o);
  }
  return o;
 }

 public void set(Object newValue)
 {
  values.put(Thread.currentThread(), newValue);
 }

 public Object initialValue()
 {
  return null;
 }
}

  当然Q这q不是一个工业强度的实现Q但JDK中的ThreadLocal的实现M思\也类g此?/p>

  ThreadLocal的?/p>

  如果希望U程局部变量初始化其它|那么需要自己实现ThreadLocal的子cdƈ重写该方法,通常使用一个内部匿名类对ThreadLocalq行子类化,比如下面的例子,SerialNumcMؓ每一个类分配一个序P

public class SerialNum
{
 // The next serial number to be assigned

 private static int nextSerialNum = 0;
 private static ThreadLocal serialNum = new ThreadLocal()
 {
  protected synchronized Object initialValue()
  {
   return new Integer(nextSerialNum++);
  }
 };

 public static int get()
 {
  return ((Integer) (serialNum.get())).intValue();
 }
}

  SerialNumcȝ使用非常地单,因ؓget()Ҏ是static的,所以在需要获取当前线E的序号Ӟ单地调用Q?/p>

int serial = SerialNum.get();

  卛_?/p>

  在线E是zd的ƈ且ThreadLocal对象是可讉K的时Q该U程持有一个到该线E局部变量副本的隐含引用Q当该线E运行结束后Q该U程拥有的所以线E局部变量的副本都将失效Qƈ{待垃圾攉器收集?/p>

  ThreadLocal与其它同步机制的比较

  ThreadLocal和其它同步机制相比有什么优势呢QThreadLocal和其它所有的同步机制都是Z解决多线E中的对同一变量的访问冲H,在普通的同步机制中,是通过对象加锁来实现多个线E对同一变量的安全访问的。这时该变量是多个线E共享的Q用这U同步机刉要很l致地分析在什么时候对变量q行dQ什么时候需要锁定某个对象,什么时候释放该对象的锁{等很多。所有这些都是因为多个线E共享了资源造成的。ThreadLocal׃另一个角度来解决多线E的q发讉KQThreadLocal会ؓ每一个线E维护一个和该线E绑定的变量的副本,从而隔M多个U程的数据,每一个线E都拥有自己的变量副本,从而也没有必要对该变量进行同步了。ThreadLocal提供了线E安全的׃n对象Q在~写多线E代码时Q可以把不安全的整个变量装qThreadLocalQ或者把该对象的特定于线E的状态封装进ThreadLocal?/p>

  ׃ThreadLocal中可以持有Q何类型的对象Q所以用ThreadLocal get当前U程的值是需要进行强制类型{换。但随着新的Java版本Q?.5Q将模版的引入,新的支持模版参数的ThreadLocal<T>cd从中受益。也可以减少强制cd转换Qƈ一些错误检查提前到了编译期Q将一定程度地化ThreadLocal的用?/p>

  ȝ

  当然ThreadLocalq不能替代同步机Ӟ两者面向的问题领域不同。同步机制是Z同步多个U程对相同资源的q发讉KQ是Z多个U程之间q行通信的有效方式;而ThreadLocal是隔d个线E的数据׃nQ从Ҏ上就不在多个U程之间׃n资源Q变量)Q这样当然不需要对多个U程q行同步了。所以,如果你需要进行多个线E之间进行通信Q则使用同步机制Q如果需要隔d个线E之间的׃n冲突Q可以用ThreadLocalQ这极大地化你的程序,使程序更加易诅R简z?br />



mlw2000 2006-08-22 12:58 发表评论
]]>
վ֩ģ壺 ˲| ʢ| Ԫ| | | Ͷ| Դ| | | | Դ| Ȩ| | | | | ӱ| ʡ| | | | | Ľ| | ά| | | | | | ϰ| | ֺ| | | ͷ| | ̩| | ϽϽ| |