??xml version="1.0" encoding="utf-8" standalone="yes"?>激情婷婷成人亚洲综合,久久亚洲精品成人无码,亚洲国产成人久久三区http://m.tkk7.com/realsmy/category/21394.html久城的学习室zh-cnMon, 17 Sep 2007 19:57:37 GMTMon, 17 Sep 2007 19:57:37 GMT60Q{QORACLE分析函数的?/title><link>http://m.tkk7.com/realsmy/articles/145916.html</link><dc:creator>久城</dc:creator><author>久城</author><pubDate>Mon, 17 Sep 2007 09:21:00 GMT</pubDate><guid>http://m.tkk7.com/realsmy/articles/145916.html</guid><wfw:comment>http://m.tkk7.com/realsmy/comments/145916.html</wfw:comment><comments>http://m.tkk7.com/realsmy/articles/145916.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/realsmy/comments/commentRss/145916.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/realsmy/services/trackbacks/145916.html</trackback:ping><description><![CDATA[     摘要: 来自Qhttp://tb.blog.csdn.net/TrackBack.aspx?PostId=1776433 分析函数是oracle816引入的一个全新的概念,为我们分析数据提供了一U简单高效的处理方式.在分析函数出C?我们必须使用自联查询,子查询或者内联视?甚至复杂的存储过E实现的语句,现在只要一条简单的sql语句可以实C,而且在执行效率方面也有相当大的提?下面我将针对分析...  <a href='http://m.tkk7.com/realsmy/articles/145916.html'>阅读全文</a><img src ="http://m.tkk7.com/realsmy/aggbug/145916.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/realsmy/" target="_blank">久城</a> 2007-09-17 17:21 <a href="http://m.tkk7.com/realsmy/articles/145916.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Q{Q重新认识面向对?http://m.tkk7.com/realsmy/articles/112048.html久城久城Thu, 19 Apr 2007 12:57:00 GMThttp://m.tkk7.com/realsmy/articles/112048.htmlhttp://m.tkk7.com/realsmy/comments/112048.htmlhttp://m.tkk7.com/realsmy/articles/112048.html#Feedback0http://m.tkk7.com/realsmy/comments/commentRss/112048.htmlhttp://m.tkk7.com/realsmy/services/trackbacks/112048.html来自Q?a href="http://m.tkk7.com/huanzhugege/archive/2007/04/10/109647.html">http://m.tkk7.com/huanzhugege/archive/2007/04/10/109647.html

l常可以从开发h员口中听?#8220;面向对象”q个词:

场景1?

AQ我今天开始用面向对象的方法设计程序了Q?

BQ你怎么做的Q?

AQ我把保存文件、加载文件封装成了一个类Q以后只要调用这个类可以实现文件操作了?

场景2?

AQ我开始学习Java了,面向对象的语aQ你不要再学VB了,好土呀Q?

BQVB怎么了?

AQVB是面向过E的Q已l过时了QJava中都是类Q很旉Q?

BQVB中也有类呀Q?

AQ(无语Q?

场景3?

AQ面向对象思想是好呀Q我真的M开Java了!

BQ你又用什么高技术了Q?

AQ我今天从一个操U|据库的类l承了一个子c,然后重写了它的保存到数据库的Ҏ(gu)Q然后把数据通过Socket发送到了远E客L了,而调用者根本不知道Q哈哈!

场景4?

AQ我推荐你用的Java不错吧?

BQ真是不错,面向对象是好,JDK里边也有好多好多的类可以用,不用像在VB里边那样要去查API文了?

AQ但是我听说现在又出了个面向斚w~程Q咱们看来又落伍了呀Q看来做~程真的不是长久之计?

写几个类是面向对象了吗Q承父cd是ؓ了重用父cȝ代码吗?覆盖父类的方法就可以瞒天qv了吗QVB中也有类Q它是面向对象吗Q?

1.1

cM对象

“c?#8221;?#8220;对象”是面向对象编E中最基本的概念,从语a的角度来Ԍ“c?#8221;是用戯定义的具有一定行为的数据cdQ?#8220;对象”则是“c?#8221;q种数据cd的变量。通俗的讲Q?#8220;c?#8221;是具有相同或怼行ؓ的事物的抽象Q?#8220;对象”?#8220;c?#8221;的实例,是是一l具有相x的代码和数据的l合体,是有一定责ȝ实体?

cLw还可以q一步抽象ؓcdQ类型是一U更高层ơ上的抽象,它只用来描述接口Q比如抽象类和接口就是一U类型。当一个类型的接口包含另外一个类型的接口Ӟ我们可以说它是此类型的子类型。类型是用来标识特定接口的,如果一个对象接受某个接口定义的所有行为,那么我们可以说该对象具有该cd。一个对象同时拥有多U类型?

面向对象~程的特?

面向对象~程有三个特性:装Q承,多态。这三个Ҏ(gu)从低到高U描qC面向对象的特征。一U语a只有同时具备q三U特性才能被UCؓ面向对象的语a。VB中也有类Q它的类也支持封装和单的l承Q但是它不支持所有的l承语义和多态,因此VB只能被称为基于对象的语言?

装是所有抽象数据类型(ADTQ的Ҏ(gu),很多刚刚接触面向对象的h认ؓ装是是面向对象。将E序按照一定的逻辑分成多个互相协作的部分,q将对外界有用的E_的部分暴露出来,而将会发生的改变隐藏hQ外界只能通过暴露的部分向q个对象发送操作请求从而n受对象提供的服务Q而不必管对象内部是如何运行的Q这是装。理解封装是理解面向对象的第一个步骤,40%的程序员寚w向对象的理解仅停留在装q个层次?

l承也称为派生,l承关系中,被承的UCؓ基类Q从基类l承而得的被UCؓzcL者子cR承是保持对象差异性的同时׃n对象怼性的复用。能够被l承的类L含有q只含有它所抽象的那一cM务的共同特点。承提供了实现复用Q只要从一个类l承Q我们就拥有了这个类的所有行为。理解承是理解面向对象的第二个步骤Q?0%的程序员寚w向对象的理解仅停留在l承q个层次。语义上?#8220;l承”表示“是一U(is-aQ?#8221;的关pR很多h体会Cl承在代码重用方面的优点Q而忽视了l承的语义特征。于是很多滥用承的情况发生了Q关于这一Ҏ(gu)们将会在后边介绍?

多态是“允许用户父对象讄成ؓ一个或更多的它的子对象相等的技术,赋值后Q基cd象就可以Ҏ(gu)当前赋值给它的zcd象的Ҏ(gu)以不同的方式运?#8221;QCharlie CalvertQ。多态扩大了对象的适应性,改变了对象单一l承的关pR多态是行ؓ的抽象,它得同名方法可以有不同的响应方式,我们可以通过名字调用某一Ҏ(gu)而无需知道哪种实现被执行Q甚x需知道执行q个实现的对象类型。多态是面向对象~程的核心概念,只有理解了多态,才能明白什么是真正的面向对象,才能真正发挥面向对象的最大能力。不q可惜的是,只有极少数程序员能真正理解多态?

对象之间的关p?/a>

对象之间有两U最基本的关p:l承关系Q组合关pR?

l承关系

l承关系可以分ؓ两种Q一U是cd接口的承,被称为接口承;另一U是cdcȝl承Q被UCؓ实现l承。承关pL一U?#8220;泛化/特化”关系Q基cM表一般,而派生类代表Ҏ(gu)?

l合关系?

l合是由已有的对象组合而成新对象的行ؓQ组合只是重复运用既有程序的功能Q而非重用其Ş式。组合与l承的不同点在于它表CZ整体和部分的关系。比如电(sh)脑是由CPU、内存、显C器、硬盘等l成的,q些部g使得?sh)脑有了计算、存储、显C图形的能力Q但是不能说?sh)脑是由CPUl承而来的?

1.2

对象之间有两U最基本的关p:l承关系Q组合关pR通过q两U关pȝ不断q代l合最l组成了可用的程序。但是需要注意的是要合理用这两种关系?

zcL基类的一个特D种c,而不是基cȝ一个角艌Ӏ语义上?#8220;l承”表示“is-a”Q是一U)的关p,zc?#8220;is-a”基类Q这是用承关pȝ最基本前提。如果类A是类B的基c,那么cB应该可以在Q何A出现的地方取代AQ这是“Liskov代换法则QLSPQ?#8221;。如果类B不能在类A出现的地方取代类A的话Q就不要把类B设计为类A的派生类?

举例来说Q?#8220;Ҏ(gu)”?#8220;水果”的派生类Q所?#8220;水果是植物的果实”q句话中?#8220;水果”可以?#8220;Ҏ(gu)”来代替:“Ҏ(gu)是植物的果实”Q?#8220;Ҏ(gu)”不是“香蕉”的派生类Q因?#8220;香蕉是一U种子退化的了的植物果实”不能?#8220;Ҏ(gu)”替换?#8220;Ҏ(gu)是一U种子退化的了的植物果实”?

举这个例子好像有点多余,不过现实的开发中却经常发?#8220;Ҏ(gu)”?#8220;香蕉”l承的事情?

某企业中有一套信息系l,其中有一?#8220;客户QCustomerQ?#8221;基础资料Q里边记录了客户的名U、地址、email{信息。后来系l要q行升Q增加一?#8220;供应商(SupplierQ?#8221;基础资料Q开发h员发?#8220;供应?#8221;中有“客户”中的所有属性,只是多了一?#8220;银行帐号”属性,所以就?#8220;供应?#8221;讄?#8220;客户”客户的子cR?

?2.1

Cq终Q老板要求l所有的客户通过Email发送新q祝,׃“供应?#8221;是一U(is-aQ?#8220;客户”Q所以系l就l?#8220;供应?#8221;?#8220;客户”都发送了新年福。第二天很多供应商都感动涕的给老板打电(sh)?#8220;谢谢老板呀Q我们供应商每次都是求着贵公怹我们的东西,Cq终你们q忘不了我们Q真是太感谢了!”。老板很茫Ӟ找来开发h员,开发h员这才意识到问题Q于是在发送Email的程序里做了判断“如果是供应商则不发送,否则发?#8221;Q一切ok了。到了年初,老板要求l所有很长时间没有购C们品的“客户”Q打?sh)话q行问候和意见征集。由?#8220;供应?#8221;是一U(is-aQ?#8220;客户”Q所以第二天?sh)话里不断出现这L回答Q?#8220;你们搞错了吧Q我们是你们的供应商呀Q?#8221;。老板大发雷霆Q开发h员这才意识到问题的严重性,所以在pȝ的所有涉及到客户的地斚w加了判断“如果是供应商?#8230;…”Q一׃改了60多处Q当然由于疏忽遗漏了两处Q所以后来又Z一ơ类似的事故?

我们可以看到错误使用l承的害处了。其实更好的解决Ҏ(gu)应该是,?#8220;客户”?#8220;供应?#8221;中抽取一个共同的基类“外部公司”出来Q?

?2.2

q样将“客户”?#8220;供应?#8221;之间的承关pd除了?

zcM应大量覆盖基cȝ行ؓ。派生类h扩展基类的责任,而不是具有覆盖(overrideQ基cȝ责Q。如果派生类需要大量的覆盖或者替换掉基类的行为,那么׃应该在两个类之间建立l承关系?

让我们再来看一个案例:

一个开发h员要设计一个入库单、一张出库单和一张盘点单Qƈ且这三张单都有登帐的功能Q通过阅读客户需求,开发h员发C张单的登帐逻辑都相同:遍历单据中的所有物品记录,然后逐笔d台帐上去。所以他p计出了如下的E序Q?

?2.3

把登帐逻辑都写C“库存业务单据”q个抽象cMQ三张单据从q个cȝ承即可。过了三个月Q用hZ新的需求:盘点单在盘点q程中,如果发现某个货物的盘亏量大于50则停止登帐,q向操作人员报警。所以开发h员在盘点单中重写?#8220;库存业务单据”?#8220;d”Ҏ(gu)Q实C客户要求的逻辑。又q了半个月,客户要求出库d的时候不仅要q行原先的登帐,q要以便d一边计出库成本。所以开发h员在出库单中重写?#8220;库存业务单据”?#8220;d”Ҏ(gu)Q实C客户要求的逻辑。到了现?#8220;库存业务单据”?#8220;d”Ҏ(gu)的逻辑只是?#8220;入库?#8221;有用了,因ؓ其他两张单据?#8220;另立门户”了?

q时候就是该我们重新梳理pȝ设计的时候了Q我们把“库存业务单据”?#8220;d”Ҏ(gu)讄成抽象方法,具体的实C码由具体子类自己军_Q?

?2.4

注意此处?#8220;库存业务单据”中的“d”Ҏ(gu)是斜体,在UML中表C此Ҏ(gu)是一个抽象方法。这个不隄解,每张单据都肯定有d行ؓQ但是每张单据的d行ؓ都有差异Q因此在抽象cM定义cȝ“d”Ҏ(gu)为抽象方法以延迟到子cMd现?

l承h如下优点Q实现新的类非常Ҏ(gu)Q因为基cȝ大部分功能都可以通过l承关系自动赋予zc;修改或者扩展承来的实现非常容易;只要修改父类Q派生的cȝ行ؓ同时被修改了?

初学面向对象~程的h会认为承真是一个好东西Q是实现复用的最好手Dc但是随着应用的深入就会发现承有很多~点Q承破坏封装性。基cȝ很多内部l节都是Ҏ(gu)生类可见的,因此q种复用?#8220;白箱复用”Q如果基cȝ实现发生改变Q那么派生类的实C随之改变。这样就D了子c行为的不可预知性;从基cȝ承来的实现是无法在运行期动态改变的Q因此降低了应用的灵zL?

l承关系有很多缺点,如果合理使用l合则可以有效的避免q些~点Q用组合关pdpȝ对变化的适应力从静态提升到动态,而且׃l合已有对象组合到了新对象中,因此新对象可以调用已有对象的功能。由于组合关pM各个各个对象的内部实现是隐藏的,我们只能通过接口调用Q因此我们完全可以在q行期用实现了同h口的另外一个对象来代替原对象,从而灵zd现运行期的行为控制。而且使用合成关系有助于保持每个类的职责的单一性,q样cȝ层次体系以及cȝ规模都不太可能增长ؓ不可控制的庞然大物。因此我们优先用组合而不是ѝ?

当然qƈ不是说承是不好的,我们可用的类L不够丰富Q而用承复用来创徏一些实用的cd会不l合来的更快Q因此在pȝ中合理的搭配使用l承和组合将会你的pȝ强大而又牢固?

1.3

接口的概?

接口是一U类型,它定义了能被其他cd现的Ҏ(gu)Q接口不能被实例化,也不能自己实现其中的Ҏ(gu)Q只能被支持该接口的其他cL提供实现。接口只是一个标识,标识了对象能做什么,至于怎么做则不在其控制之内,它更像一个契U?

M一个类都可以实C个接口,q样q个cȝ实例可以在M需要这个接口的地方起作用,q样pȝ的灵zL就大大增强了?

接口~程的实?

SQL语句在各个不同的数据库之间移植最大的ȝ是各个数据库支持的语法不尽相同Q比如取的前10行数据在不同数据库中有不同的实现?

MSSQLServerQSelect top 10 * from T_Table

MySQL:select * from T_Table limit 0,10

Oracle:select * from T_Table where ROWNUM <=10

我们先来看一下最朴素的做法是怎样的:

首先定义一个SQL语句译器类Q?

public class Test1SQLTranslator

{

private int dbType;

public Test1SQLTranslator(int dbType)

{

super();

this.dbType = dbType;

}

public String translateSelectTop(String tableName, int count)

{

switch (dbType) {

case 0:

return "select top " + count + " * from " + tableName;

case 1:

return "select * from " + tableName + " limit 0," + count;

case 2:

return "select * from " + tableName + " where ROWNUM<=" + count;

default:

return null;

}

}

}

然后如下调用

public static void main(String[] args)

{

String tableName = "T_Table";

int count = 10;

int dbType = 0;

Test1SQLTranslator translator = new Test1SQLTranslator(dbType);

String sql = translator.translateSelectTop(tableName,count);

System.out.println(sql);

}

如果要增加对新的数据库的支持Q比如DB2Q那么就必须修改Test1SQLTranslatorc,增加一个对DB2的case语句Q这U增加只能是在编辑源码的时候进行添加,无法在运行时动态添加。再来看一下如果用Z接口的编E方式是如何实现的?

首先Q定义接口ISQLTranslatorQ这个接口定义了所有SQL译器的Ҏ(gu)Q目前只有一个翻译Select top的方法:

public interface ISQLTranslator

{

public String translateSelectTop(String tableName, int count);

}

接着我们为各个数据库写不同的译器类Q这些翻译器c都实现了ISQLTranslator接口Q?

public class MSSQLServerTranslator implements ISQLTranslator

{

public String translateSelectTop(String tableName, int count)

{

return "select top " + count + " * from " + tableName;

}

}

public class MySQLTranslator implements ISQLTranslator

{

public String translateSelectTop(String tableName, int count)

{

return "select * from " + tableName +" limit 0,"+count;

}

}

public class OracleSQLTranslator implements ISQLTranslator

{

public String translateSelectTop(String tableName, int count)

{

return "select * from " + tableName+" where ROWNUM<="+count;

}

}

如下调用Q?

public static void main(String[] args)

{

String tableName = "T_Table";

int count = 10;

ISQLTranslator translator = new MSSQLServerTranslator();

String sql = translator.translateSelectTop(tableName, count);

System.out.println(sql);

}

q行以后Q打印出了:

select top 10 from T_Table

可以看到Q不同的数据库翻译实现由不同的类来承担,q样最大的好处是可扩展性极强,比如也许某一天出C了支持中文语法的数据库,我要为它做翻译器只需再增加一个类Q?

public class SinoServerTranslator implements ISQLTranslator

{

public String translateSelectTop(String tableName, int count)

{

return "d?+tableName+"的前"+count+"?;

}

}

修改调用代码Q?

public static void main(String[] args)

{

String tableName = "T_Table";

int count = 10;

ISQLTranslator translator = new SinoServerTranslator();

String sql = translator.translateSelectTop(tableName, count);

System.out.println(sql);

}

q行后控制台打印出:

d表T_Table的前10?

q里的translator 可以随意实例化,只要实例化的cdCISQLTranslator 可以了Q这个类也可以通过配置文gdQ甚x其他cM递过来的Q这都无所谓,只要是实CISQLTranslator 接口它就能正常工作?

如果要给SQL语句加上验证功能Q也是译的时候首先验证一下翻译的l果是否能在数据库中执行Q我们就可以采用偷天换日的方式来q行?

首先创徏一个VerifyTranslatorc:

public class VerifyTranslator implements ISQLTranslator

{

private ISQLTranslator translator;

private Connection connection;

public VerifyTranslator(ISQLTranslator translator, Connection connection)

{

super();

this.translator = translator;

this.connection = connection;

}

public String translateSelectTop(String tableName, int count)

{

String sql = translator.translateSelectTop(tableName, count);

PreparedStatement ps = null;

try

{

ps = connection.prepareStatement(sql);

ps.execute();

} catch (SQLException e)

{

DbUtils.close(ps);

return "wrong sql";

}

return sql;

}

}

q个cL受一个实CISQLTranslator 接口的变量和数据库连接做为构造参敎ͼ最重要的是q个cLw也实现了ISQLTranslator 接口Q这样它?yu)完全?#8220;伪装”成SQL译器来行ɾ译的责MQ不q它没有真正执行译Q它把翻译的d转发l了通过构造函C递来的那个翻译器变量Q?

String sql = translator.translateSelectTop(tableName, count);

它自q真正d则是q行SQL语句的验证:

ps = connection.prepareStatement(sql);

再次修改调用代码Q?

public static void main(String[] args)

{

String tableName = "T_Table";

int count = 10;

ISQLTranslator translator = new VerifyTranslator(

new SinoServerTranslator(), getConnection());

String sql = translator.translateSelectTop(tableName, count);

System.out.println(sql);

}

q行后控制台打印出:

wrong sql

下面q段代码看上L不是很眼熟呢Q?

ISQLTranslator translator = new VerifyTranslator(new SinoServerTranslator(), getConnection());

q段代码和我们经常写的流操作非常cMQ?

InputStream is = new DataInputStream(new FileInputStream(new File(“c:/boot.ini”)));

q就是设计模式中l常提到?#8220;装饰者模?#8221;?

针对接口~程

从上面的例子我们可以看出Q当代码写到Q?

String sql = translator.translateSelectTop(tableName, count);

的时候,代码~写者根本不兛_translatorq个变量到底是哪个类的实例,它只知道它调用了接口U定支持的translateSelectTopҎ(gu)?

当一个对象需要与其他对象协作完成一Q务时Q它?yu)需要知道那个对象,q样才能调用那个对象的方法来获得服务Q这U对象对另一个协作对象的依赖叫做关联。如果一个关联不是针对具体类Q而是针对接口的时候,M实现q个接口的类都可以满求,因ؓ调用者仅仅关心被依赖的对象是不是实现了特定接口?

当发送的h和具体的h响应者之间的关系在运行的时候才能确定的时候,我们q之ؓ动态绑定。动态绑定允许在q行期用h相同接口的对象进行替换,从而实现多态。多态得对象间彼此独立Q所有的交互操作都通过接口q行Qƈ可以在运行时改变它们之间的依赖关pR?

针对接口~程Q而不是针对实现编E是面向对象开发中的一个非帔R要的原则Q也是设计模式的_NQ?

针对接口~程有数不清的例子,比如在Hibernate中,集合属性必d明ؓSet、Map、List{接口类型,而不能声明ؓHashSet、HashMap、ArrayList{具体的cdQ这是因为Hibernate在ؓ了实现LazyLoadQ自己开发了能实现LazyLoad功能的实CSet、Map、List{接口的c,因ؓ我们的属性的cd只声明ؓq些属性ؓq些接口的类型,因此Hibernate才敢攑ֿ大胆的返回这些特定的实现cR?

现实的开发过E中有如下一些违反针Ҏ(gu)口编E原则的陋习Q?

陋习1

ArrayList list = new ArrayList();

for(int i=0;i<10;i++)

{

list.add(……);

}

q里使用的是ArrayList的addҎ(gu)Q而addҎ(gu)是定义在List接口中的Q因此没有必要声明list变量为ArrayListcdQ修改如下:

List list = new ArrayList();

for(int i=0;i<10;i++)

{

list.add(……);

}

陋习2

public void fooBar(HashMap map)

{

Object obj = map.get(“something”);

……

}

在这个方法中只是调用Map接口的getҎ(gu)来取数据Q所以就不能要求调用者一定要传递一个HashMapcd的变量进来。修改如下:

public void fooBar(Map map)

{

Object obj = map.get(“something”);

……

}

q样修改以后用户Z防止传递给fooBarҎ(gu)的Map被修改,用户可以这栯用了Q?

Map unModMap = Collections.unmodifiableMap(map);

obj.fooBar(unModMap);

Collections.unmodifiableMap是JDK提供的一个工LQ可以返回一个对map的包装,q回的map是不可修改的Q这也是装饰者模式的典型应用?

试想如果我们把接口声明ؓpublic void fooBar(HashMap map)用户q能q么调用吗?

1.4 抽象c?/h4>

抽象cȝ主要作用是为它的派生类定义公共接口Q抽象类把它的部分操作的实现延迟到派生类中来Q派生类也能覆盖抽象基类的方法,q样可以很容易的定义新类。抽象类提供了一个承的出发点,我们l常定义一个顶层的抽象c,然后某些位|的实现定义为抽象的Q也是我们仅仅定义了实现的接口Q而没有定义实现的l节?

一个抽象类应该可能多的拥有共同的代码Q但是不能把只有特定子类才需要的Ҏ(gu)Ud到抽象类中。Eclipse的某些实现方式在q一点上做的不是很好,Eclipse的一些界面类中提供了诸如CreateEmailField之类的方法来创徏界面对象Q这些方法ƈ不是所有子c都用得到的Q应该把它们抽取C个工L中更好。同L错误在我们的案例的JCownewDialog中也是存在的Q这个类中就提供了CreateOKBtn、CreateCanceBtn两个Ҏ(gu)用来创徏定、取消按钮?

在设计模式中Q最能体现抽象类优点的就是模版方法模式。模版方法模式定义了一个算法的骨架Q而具体的实现步骤则由具体的子cȝ来实现。JDK中的InputStreamcL模版Ҏ(gu)的典型代表,它对skip{方法给Z实现Q而将read{方法定义ؓ抽象Ҏ(gu){待子类d现。后Ҏ(gu)例中的PISAbstractAction{类也是模版Ҏ(gu)的一个应用?

在实际开发中接口和抽象类从两个方向对pȝ的复用做Z贡献Q接口定义了pȝ的服务契U,而抽象类则ؓq些服务定义了公q实现Q子cd全可以从q些抽象cȝ承,q样׃用自己实现自己所不关心的Ҏ(gu)Q如果抽象类提供的服务实C满自己的要求,那么可以自׃头实现接口的服务契约?



久城 2007-04-19 20:57 发表评论
]]>Q{Q谈谈我对Java中Unicode、编码的理解http://m.tkk7.com/realsmy/articles/110789.html久城久城Sun, 15 Apr 2007 08:41:00 GMThttp://m.tkk7.com/realsmy/articles/110789.htmlhttp://m.tkk7.com/realsmy/comments/110789.htmlhttp://m.tkk7.com/realsmy/articles/110789.html#Feedback0http://m.tkk7.com/realsmy/comments/commentRss/110789.htmlhttp://m.tkk7.com/realsmy/services/trackbacks/110789.html

我们l常会遇到编码问题?/span>JavaL国际化的语言Q是因ؓ它的class文g采用UTF-8Q?/span>JVMq行时?/span>UTF-16Q至于ؓ什?/span>JVM中要采用UTF-16Q我没看q?/span> 相关的资料,但我猜可能是因ؓJAVA里面一个字W?/span>(char)16位的Q而UTF-16正是双字节编码)Q都?/span>unicode的编码?/span>

unicode
的目标就是能支持世界上所有的字符集,也就是说几乎所有的字符集包含的字符?/span>unicode中都有对应的~码。在unicode中,字符与代码的映射?/span> p,是unicode字符集,UCؓUCS(Unicode Character Set)Q每?/span>unicode字符~码UCؓcode pointQ代码点Q)?/span>UTF-8?/span>UTF-16是不同的UCS~码Ҏ(gu)Q?/span>UTFUCS Transformation Format?

?/span>Java 中,String?/span>getBytes()Ҏ(gu)是对特定的字符?/span>(unicode)按照l定的字W集q行~码Q?/span>encodeQ,new String()则可以按照某个字W集字节流转换?/span>unicodeQ?/span>decodeQ?/span>Java里面的每一?/span>String都是unicode~码?/span>

再来看页面,如果不做Ҏ(gu)处理Q?/span>Form的提交就按照面?/span>ContentType讄中的字符集进行编码{换,发送到后台Q后台必d?/span>req.setCharacterEncoding来指定参数的~码格式(不同的应用服务器应有不同的指定方?/span>)Q才能正解码?/span>

Java
里面?/span>encode?/span>decode都是相对?/span>unicode而言的,encode的意思是?/span>char[] --> XXX Encoding byte[]Q?/span>decode是?/span>XXX Encoding byte[] --> char[]。^常,当我们说?/span>GBK~码转换?/span>UTF-8~码的时候,实际的意思就是:GBK Encoding byte[] --> UTF-8 Encoding byte[]Q这U{换只有在需要用byte[]传输数据的时候才有意义,否则便是毫无意义的?/span>

首先要说明的一Ҏ(gu)Q?/span>Java中的String对象是一?/span>unicode~码的字W串?/span>

但是Q我们通常会听到有Q?/span>我们需要将String?/span>ISO-8859-1转换?/span>GBK~码Q这又是怎么回事呢?实际上,我们q?strong>不是?/span>?/span> 一个由ISO-8859-1~码?/span>String转换?/span>GBK~码?/span>String”Q反复说明的是,JAVA中的String都是unicode~码的,所以不存在“ISO- 8859-1~码?/span>String”?/span>“GBK~码?/span>String”q样的说法。而需要{换的唯一的原因是Stringq行了错误的~码。我们经怼到?/span>ISO-8859- 1转换?/span>GBK/UTF-8{等q样的需求。所谓的转换q程是:String --> byte[] -->String?/span>
也许 你非常清楚这个过E的代码Q?/span>new String(text.getBytes("ISO-8859-1"),"GBK")。但是,要真正理解v来ƈ不是那么单。表面上看似乎很Ҏ(gu)理解Q?/span> 不就是将text String对象按照ISO-8859-1的方式编码ؓbyte[]然后再把它按?/span>GBK的方式{换ؓString吗?但是q句代码很容易会被误解ؓQ?/span>?/span>text String?/span>ISO-8859-1转换?/span>GBK~码Q这U说法是错误的。难道你见过用这L代码Q?/span>new String(text.getBytes("GBK"),"UTF-8")来对Stringq行~码转换的吗Q?/span>

之所以你会经常看?/span>new String(text.getBytes("ISO-8859-1"),"GBK")q句代码Q是因ؓ一?/span>GBK的字节流被错误地?/span>ISO-8859- 1的方式{换ؓStringQ?/span>unicodeQ了Q发生这U情冉|普遍的地Ҏ(gu)一?/span>GBK~码的网向后台提交数据的时候,有可能会看到这句代码的?/span> 现?/span>GBK的流被错误的当成ISO8859-1的流Q所以便得到了一个错误的String。由?/span>ISO8859-1是单字节~码Q所以每个字节被按照原样 转换?/span>StringQ也是_虽然q是一个错误的转换Q但~码没有改变Q所以我们仍然有Z把编码{换回来!所以那句经典的new String(text.getBytes("ISO-8859-1"),"GBK")便出C?/span>

如果pȝ误以为是其它~码格式Q就有可能再也{换不回来了,因ؓ~码转换q不是负负得正那么简单的 



久城 2007-04-15 16:41 发表评论
]]>
Q{Q学习JAVA?0个目?/title><link>http://m.tkk7.com/realsmy/articles/110493.html</link><dc:creator>久城</dc:creator><author>久城</author><pubDate>Fri, 13 Apr 2007 09:14:00 GMT</pubDate><guid>http://m.tkk7.com/realsmy/articles/110493.html</guid><wfw:comment>http://m.tkk7.com/realsmy/comments/110493.html</wfw:comment><comments>http://m.tkk7.com/realsmy/articles/110493.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/realsmy/comments/commentRss/110493.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/realsmy/services/trackbacks/110493.html</trackback:ping><description><![CDATA[<p>1.你需要精通面向对象分析与设计(OOA/OOD)、涉及模?GOFQJ2EEDP)以及l合模式。你应该十分了解UMLQ尤其是classQobjectQinteraction以及statediagrams?/p> <p>  2.你需要学习JAVA语言的基知识以及它的核心cd(collectionsQserializationQstreamsQnetworkingQ?multithreadingQreflectionQeventQhandlingQNIOQlocalizationQ以及其??/p> <p>  3.你应该了解JVMQclassloadersQclassreflectQ以及垃圑֛收的基本工作机制{。你应该有能力反~译一个类文gq且明白一些基本的汇编指o?/p> <p>  4.如果你将要写客户端程序,你需要学习WEB的小应用E序(applet)Q必需掌握GUI设计的思想和方法,以及桌面E序的SWINGQAWTQ?SWT。你q应该对UI部g的JAVABEANlg模式有所了解。JAVABEANS也被应用在JSP中以把业务逻辑从表现层中分d来?/p> <p>  5.你需要学习java数据库技术,如JDBCAPIq且会用至一Upersistence/ORM构架Q例如HibernateQJDOQ?CocoBaseQTopLinkQInsideLiberator(国JDOU工厂Y?或者iBatis?/p> <p>  6.你还应该了解对象关系的阻抗失配的含义Q以及它是如何媄响业务对象的与关pd数据库的交互Q和它的q行l果Q还需要掌握不同的数据库品运用,比如:oracleQmysqlQmssqlserver?/p> <p>  7.你需要学习JAVA的沙盒安全模?classloadersQbytecodeverificationQmanagersQpolicyandpermissionsQ?br>codesigningQ?digitalsignaturesQcryptographyQcertificationQKerberosQ以及其?q有不同的安?认证 APIQ例如JAAS(JavaAuthenticationandAuthorizationService)QJCE (JavaCryptographyExtension)QJSSE(JavaSecureSocketExtension)Q以及JGSS (JavaGeneralSecurityService)?/p> <p>  8.你需要学习ServletsQJSPQ以及JSTL(StandardTagLibraries)和可以选择的第三方TagLibraries?/p> <p>  9.你需要熟(zhn)主的|页框架Q例如JSFQStrutsQTapestryQCocoonQWebWorkQ以及他们下面的涉及模式Q如MVC/MODEL2?/p> <p>  10.你需要学习如何用及理WEB服务器,例如tomcatQresinQJrunQƈ且知道如何在其基上扩展和l护WEBE序?/p> <p> 11.你需要学习分布式对象以及q程APIQ例如RMI和RMI/IIOP?<br>  12.你需要掌握各U流行中间g技术标准和与javal合实现Q比如Tuxedo、CROBAQ当然也包括javaEE本n?/p> <p>  13.你需要学习最一U的XMLAPIQ例如JAXP(JavaAPIforXMLProcessing)QJDOM(JavaforXMLDocumentObjectModel)QDOM4JQ或JAXR(JavaAPIforXMLRegistries)?/p> <p>  14.你应该学习如何利用JAVAAPI和工h构徏WebService。例如JAX-RPC(JavaAPIforXML/RPC)QSAAJ (SOAPwithAttachmentsAPIforJava)QJAXB(JavaArchitectureforXMLBinding)QJAXM(JavaAPIforXMLMessaging)Q?JAXR(JavaAPIforXMLRegistries)Q或者JWSDP(JavaWebServicesDeveloperPack)?/p> <p>  15.你需要学习一门轻量应用E序框架Q例如SpringQPicoContainerQAvalonQ以及它们的IoC/DI风格(setterQconstructorQinterfaceinjection)?/p> <p>  16.你需要熟(zhn)不同的J2EE技术,例如JNDI(JavaNamingandDirectoryInterface)QJMS (JavaMessageService)QJTA/JTS(JavaTransactionAPI/JavaTransactionService)QJMX (JavaManagementeXtensions)Q以及JavaMail?/p> <p>  17.你需要学习企业JavaBeans(EJB)以及它们的不同组件模式:Stateless/StatefulSessionBeansQEntityBeans(包含Bean- ManagedPersistence[BMP]或者Container-ManagedPersistence[CMP]和它的EJB-QL)Q或?Message-DrivenBeans(MDB)?/p> <p>  18.你需要学习如何管理与配置一个J2EE应用E序服务器,如WebLogicQJBoss{,q且利用它的附加服务Q例如簇c,q接池以及分布式处理支援。你q需要了解如何在它上面封装和配置应用E序q且能够监控、调整它的性能?/p> <p>  19.你需要熟(zhn)面向方面的E序设计以及面向属性的E序设计(q两个都被很Ҏ(gu)h的羃写ؓAOP)Q以及他们的LJAVA规格和执行。例如AspectJ和AspectWerkz?/p> <p>  20.你需要熟(zhn)对不同有用的API和frame work{来Z服务。例如Log4J(logging/tracing)QQuartz (scheduling)QJGroups(networkgroupcommunication)QJCache(distributedcaching)Q?Lucene(full-textsearch)QJakartaCommons{等?/p> <p>21.如果你将要对接或者正和旧的系l或者本地^収ͼ你需要学习JNI (JavaNativeInterface) and JCA (JavaConnectorArchitecture)?/p> <p>  22.你需要熟(zhn)JINI技术以及与它相关的分布式系l,比如掌握CROBA?/p> <p>  23.你需要JavaCommunityProcess(JCP)以及他的不同JavaSpecificationRequests(JSRs)Q例如Portlets(168)QJOLAP(69)QDataMiningAPI(73)Q等{?/p> <p>  24.你应该熟l掌握一UJAVAIDE例如sunOneQnetBeansQIntelliJIDEA或者Eclipse?有些人更喜欢VI或EMACS来编写文件。随便你用什么了Q?</p> <p>  25.JAVA(_的说是有些配|?是冗长的Q它需要很多的人工代码(例如EJB)Q所以你需要熟(zhn)代码生成工P例如XDoclet?/p> <p>  26.你需要熟(zhn)一U单元测试体p?JNunit)Qƈ且学习不同的生成、部|工?AntQMaven)?/p> <p>  27.你需要熟(zhn)一些在JAVA开发中l常用到的Y件工E过E。例如RUP(RationalUnifiedProcess)andAgilemethodologies?/p> <p>  28.你需要能够深入了解加熟练操作和配|不同的操作pȝQ比如GNU/linuxQsunsolarisQmacOS{,做ؓ跨^台Y件的开发者?/p> <p>  29.你还需要紧跟java发展的步伐,比如现在可以深入的学习javaMEQ以及各Ujava新规范,技术的q用Q如新v的web富客L技术?/p> <p>  30.你必需要对opensource有所了解Q因java的很多技术直接是靠开源来驱动发展的,如java3D技术?br></p> <img src ="http://m.tkk7.com/realsmy/aggbug/110493.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/realsmy/" target="_blank">久城</a> 2007-04-13 17:14 <a href="http://m.tkk7.com/realsmy/articles/110493.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Q{Q初探Javacd载机?/title><link>http://m.tkk7.com/realsmy/articles/109210.html</link><dc:creator>久城</dc:creator><author>久城</author><pubDate>Sun, 08 Apr 2007 02:59:00 GMT</pubDate><guid>http://m.tkk7.com/realsmy/articles/109210.html</guid><wfw:comment>http://m.tkk7.com/realsmy/comments/109210.html</wfw:comment><comments>http://m.tkk7.com/realsmy/articles/109210.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/realsmy/comments/commentRss/109210.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/realsmy/services/trackbacks/109210.html</trackback:ping><description><![CDATA[     摘要: 此文章由教程中国(http://www.upschool.com.cn)提供    一、在jdk1.2以后Q类加蝲是通过委托来完成的Q这意味着如果 ClassLoader 不能扑ֈc,它会h父代 ClassLoader 来执行此Q务,所?ClassLoaders 的根是系l?ClassLoaderQ它会以~省方式装入c?-- 卻I从本地文件系l。今天我们就来探?..  <a href='http://m.tkk7.com/realsmy/articles/109210.html'>阅读全文</a><img src ="http://m.tkk7.com/realsmy/aggbug/109210.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/realsmy/" target="_blank">久城</a> 2007-04-08 10:59 <a href="http://m.tkk7.com/realsmy/articles/109210.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Q{Q理解Javacd载原?译) http://m.tkk7.com/realsmy/articles/109198.html久城久城Sun, 08 Apr 2007 02:11:00 GMThttp://m.tkk7.com/realsmy/articles/109198.htmlhttp://m.tkk7.com/realsmy/comments/109198.htmlhttp://m.tkk7.com/realsmy/articles/109198.html#Feedback0http://m.tkk7.com/realsmy/comments/commentRss/109198.htmlhttp://m.tkk7.com/realsmy/services/trackbacks/109198.html我需要读q篇文章吗?
Javacd载器对Javapȝ的运行是臛_重要的,但是却常常被我们忽略。Javacd载器负蝲
在运行时查找和加载类。自定义cd载器可以完全改变cȝ加蝲方式Q以自己喜欢的方式来
个性化你的Java虚拟机。本文简要的介绍Javacd载器Q然后通过一个构造自定义cd载器
的例子来说明Q这个类加蝲器在加蝲cd会自动编译代码。你学到类加蝲器到底是q什?br>的,如何创徏你自qcd载器。只要你有一些基本的Java知识Q知道如何创建、编译、运
行一个命令行JavaE序以及一些JavacL件的基本概念Q你可以理解本文的内容了。读?br>本文Q你应该能够Q?br>* 扩张Java虚拟机的功能
* 创徏一个自定义的类加蝲?br>* 如何把自定义的类加蝲器整合到你的应用E序?br>* 修改你的cd载器以兼容JavaQ?br>获得帮助 
Ҏ(gu)文有M问题Q可以联pM者Greg TravisQa:mito@panix.com ?br>W二部分. ?br>cd载器是什么?
Java和其他语a不同的是QJava是运行于Java虚拟?JVM)。这意味着~译后的代码是以
一U和q_无关的格式保存的Q而不是某U特定的机器上运行的格式。这U格式和传统的可
执行代码格式有很多重要的区别。具体来_不同于C或者E++E序QJavaE序不是一个独
立的可执行文Ӟ而是由很多分开的类文gl成Q每个类文g对应一个JavacR?另外Q这
些类文gq不是马上加载到内存Q而是当程序需要的时候才加蝲?cd载器是Java虚拟
Z用来把类加蝲到内存的工具。而且QJavacd载器也是用Java实现的。这样你׃需?br>对Java虚拟机有深入的理解就可以很容易创qcd载器了?br>Z么要创徏cd载器?
既然Java虚拟金已l有了类加蝲器,我们q要自己创徏其他的呢?问得好。默认的cd载器
只知道如何从本地pȝ加蝲cR当你的E序完全在本机编译的话,默认的类加蝲器一般都?br>作的很好。但是Java中最Ȁ动h心的地方之一是很容易的从网l上而不只是本地加蝲cR?br>举个例子Q浏览器可以通过自定义的cd载器加蝲cR?q有
很多加蝲cȝ方式。除了简单的从本地或者网l外Q你q可以通过自定义Java中最Ȁ动h?br>的地方之一:
* 执行非信M码前自动验证数字{֐
* Ҏ(gu)用户提供的密码解密代?br>* Ҏ(gu)用户的需要动态的创徏c?br>你关心的M东西都能方便的以字节码的形式集成C的应用中
自定义类加蝲器的例子
如果你已l用过JDK(Java软g开发包)中的appletviewerQ小应用E序览器)或者其?br>Java嵌入式浏览器Q你已l用了自定义类加蝲器了。Sun刚刚发布Java语言的时候,最
令h兴奋的一件事是观看Java如何执行从远E网站下载的代码。执行从q程站点通过HTT
Pq接传送来的字节码看v来有点不可思议。之所以能够工作,因ؓJava有安装自定义cd
载器的能力。小应用E序览器包含了一个类加蝲器,q个cd载器不从本地找Javac,?br>是访问远E服务器Q通过HTTP加蝲原始字节码文Ӟ然后在Java虚拟Z转化为JavacR当
然类加蝲器还做了其他的很多事情:他们L不安全的Javac,而且保持不同面上的不同
程序不会互相干扰。Luke Gorrie写的一个包Echidna是一个开攄Java软g包,他允许在
一个Java虚拟Z安全的运行多个Java应用E序。它通过使用自定义类加蝲器给每个应用E?br>序一份类文g的拷贝来L应用E序之间的干扰?br>我们的类加蝲器例?br>我们知道了类加蝲器是如何工作的,也知道如何定义自qcd载器了,接下来我们创Z
个名字ؓCompilingClassLoader (CCL)的自定义cd载器。CCL为我们做~译工作Q我们就
不用自己手动~译了?q基本上相当于有一?make"E序构徏到我们的q行环境?br>注意Q我们进行下一步之前,有必要搞清楚一些相关的概念?br>pȝ在JDK版本1.2Q也是我们说的Java 2q_Q得到很到改q。本文是在JDK1.0?.1?br>版本下写的,但是所有的东西都能在后来的版本工作。ClassLoader也在Java2U有所改进Q?br>W五部分有详l介l?br>W三部分.ClassLoader的结?br>L
cd载器的基本目的是服务于对Javacȝh。Java虚拟机需要一个类的时候,把一个类
名给cd载器,然后cd载器试图q回一个对应的cd例。可以通过在不同的阶段覆盖相应
的方法来创徏自定义的cd载器。接下来我们了解到cd载器的一些主要方法。你会明?br>q些Ҏ(gu)是干什么的Q他们在加蝲cL件的时候是如何工作的。你q将知道创徏自定义类?br>载器的时候需要写哪些代码。在下一部分Q你利用这些知识和我们自定义的CompilingCl
assLoader一起工作?br>Ҏ(gu) loadClass
ClassLoader.loadClass() 是ClassLoader的入口点。方法签名如下:
Class loadClass( String name, boolean resolve);
参数name指定Java虚拟机需要的cȝ全名(含包?Q比如Foo或者java.lang.Object?br>参数 resolve指定该类是否需要解?br>你可以把cȝ解析理解为完全ؓq行做好准备。解析一般都不需要。如果Java虚拟机只想知
道这个类是否存在或者想知道它的父类的话Q解析就完全没有必要了?在Java1.1和它以前
的版本,如果要自定义cd载器,loadClassҎ(gu)是唯一需要在子类中覆盖的Ҏ(gu).
(ClassLoader在Java1.2中有所改变Q提供了Ҏ(gu)findClass())?br>Ҏ(gu) defineClass
defineClass 是ClassLoader中一个很秘的方法。这个方法通过一个字节数l来构徏cd
例。这个包含数据的原始字节数组可能来自文gpȝQ也可能是来自网l。defineClass ?br>明了Java虚拟机的复杂性,秘性和q_依赖?它通过解释字节码把它{化ؓq行时数?br>l构Q检查有效性等{。但是不用担心,q些都不用你d现。其实,你根本不能覆盖它Q?br>因ؓ该方法被关键字final修饰?br>Ҏ(gu) findSystemClass
findSystemClassҎ(gu)从本地系l加载文件。它在本地系l寻扄文gQ如果找CQ调?br>defineClass把原始字节数l{化成cd象。这是运行Java应用时Java虚拟机加载类的默?br>机制。对于自定义cd载器Q只有在我们无法加蝲之后才需要用findSystemClass?原因?br>? 我们的类加蝲器负责执行类加蝲中的某些特定的步骤,但ƈ不是Ҏ(gu)有的cR比如,
即我们的类加蝲器从q程站点加蝲了某些类Q仍然有很多基本的类要从本地pȝ加蝲?br>q些cM是我们关心的Q所以我们让Java虚拟Z默认的方式加载他们:从本地系l。这?br>是findSystemClass做的事情。整个过E大致如下:
* Java虚拟求我们自定义的类加蝲器加载类?br>* 我们查远E站Ҏ(gu)否有q个需要加载的cR?br>* 如果有,我们获取q个cR?br>* 如果没有Q我们认个是cd基本cd中,调用findSystemClass从文件系l中加蝲?br>
在大多数自定义类加蝲器中Q你应该先调用findSystemClass来节省从q程查找的时间?br>实际上,正如我们在下一部分看到的,只有当我们确定我们已l自动编译完我们的代码后
才允许Java虚拟Z本地文gpȝ加蝲cR?br>Ҏ(gu)resolveClass
正如上面说的Q类记蝲可以分ؓ部分加蝲Q不解析Q和完全加蝲Q包括解析)。我们创
定义cd载器的时候,可能要调用resolveClass?br>Ҏ(gu) findLoadedClass
findLoadedClass实现一个缓?当要求loadClass来加载一个类的时候,可以先调用这个方
法看看这个类是否已经被加载,防止重新加蝲一个已l被加蝲的类。这个方法必d被调?br>Q我们看一下这些方法是如何l织在一L?br>我们的例子实现l(f)oadClass执行以下的步骤。(我们不指定通过某种具体的技术获得类文g
Q?它可能从|络Q从压羃包或者动态编译的。无论如何,我们获得的是原始字节码文Ӟ
* 调用findLoadedClass查这个类是否已经加蝲?br>* 如果没有加蝲Q我们通过某种方式获得原始字节数组?br>* 假如已经获得该数l,调用defineClass把它转化成类对象?br>* 如果无法获得该原始字节数l,调用findSystemClass 查是否可以从本地文gpȝ中记
载?br>* 如果参数resolve为true,调用resolveClass来解析类对象?br>* 如果q没有找到类Q抛Z个ClassNotFoundException异常?br>* 否则Q返回这个类?br>现在我们对类加蝲器的应用知识有个较全面的了解Q可以创定义cd载器了。在下一?br>分,我们讨论CCL?br>W四部分. CompilingClassLoader
CCLl我们展CZcd载器的功? CCL的目的是让我们的代码能够自动~译和更新。下面描
q它是怎么工作的:
* 当有一个类的请求时Q先查磁盘的当前目录和子目录上是否存在这个类文g?br>* 如果没有cLӞ但是却有源代码文Ӟ调用Java~译器编译生成类文g?br>* 如果cL件已l存在,查该cL件是否比源代码文仉旧。如果类文g比源代码文g?br>旧,调用Java~译器重新生成类文g?br>* 如果~译p|Q或者由于其他原因导致无法从源文件生成类文gQ抛出异常ClassNotFou
ndException?br>* 如果q没有获得这个类Q可能存在其他的cd里,调用findSystemClass看是否能扑ֈ?br>
* 如果没有扑ֈQ抛出异常ClassNotFoundException?br>* 否则Q返回该cR?br>Java~译是如何实现的Q?br>在我们进一步讨论前Q我们需要先弄清楚Java的编译过E。通常QJava~译器不仅仅~译?br>定的那些cR如果指定的那些c需要的话,它还会编译其它的一些相关类。CCL会一个一?br>的编译我们在应用E序中需要编译的那些cR不q,一般来_~译器编译完W一个类后,
CCL会发现其实其他需要的相关cdl被~译了。ؓ什么呢QJava~译器用我们差不多
的规则:如果一个了cM存在或者源文g已经被更斎ͼ׃~译q个cRJava~译器基本上
比CCL早了一步,大部分工作都被Java~译器完成了。我们看h像是CCL在编译这些类?br>在大多数情况下,你将发现它是在主函数cM调用~译器,׃仅这些而已--单的一个调
用就够了?不过有一U特D情况,q些cdW一ơ出现的时候不~译。如果你Ҏ(gu)cd?br>载一个类Q用方法Class.forName,Java~译器ƈ不知道是否需要这个类。在q种情况下,
你发现CCL再次调用~译器来~译该类。第六部分的代码说明了这个过E?br>使用CompilationClassLoader
Z使用CCL,我们不能直接q行我们的程序,必须以一U特D的方式q行Q就像这P
% java Foo arg1 arg2
我们q样q行?
% java CCLRun Foo arg1 arg2
CCLRun是一个特D的存根E序Q它来创建CompilingClassLoader q且用它来加载我们的?br>函数c?q样可以保所有的整个E序都是由CompilingClassLoader加蝲的。CCLRun利用Ja
va反射API来调用主函数cȝd数ƈ且给q个函数传递参数。想了解更多Q参考第六部?br>的源代码?br>q行CZ
我们演示一下整个过E式怎么工作的?br>ȝ序是一个叫做Foo的类Q它创徏一个类Bar的实例。这个Bar实例又创Z个类Baz的实?br>Q类Baz存在于包baz中,q是Z演示CCL如何从子包中加蝲cRBarq根据类名加载类Boo
Q这个也是CCL完成的。所有的c都加蝲了就可以q行了。利用第六章的源代码来执行这?br>E序。编译CCLRun和CompilingClassLoader。确保你没有~译其它的类(Foo, Bar, Baz, a
nd Boo)Q否则CCL不起作用,?br>% java CCLRun Foo arg1 arg2
CCL: Compiling Foo.java...
foo! arg1 arg2
bar! arg1 arg2
baz! arg1 arg2
CCL: Compiling Boo.java...
Boo!
注意Cؓ了Foo.javaW一ơ调用编译器Q同时也把Bar和baz.Baz一L译了俄。而类Boo
直道需要加载的时候,CCL才再ơ调用编译器来编译它?br>W五部分.Java2中对cd载器的改q?br>概览
在Java1.2和以后的版本? cd载器有了很大的改q。以前的代码仍然可以工作Q?但是?br>的系l让我们的实现更Ҏ(gu)。这U新模型是代理委托模型Q就是说如果q个cd载器找不
到某个类Q它会让他的父类加蝲器来找。系l类加蝲器是所有类加蝲器的先, pȝcd?br>器通过默认的方式加载类--也就是从本地文gpȝ中加载。覆盖loadClassҎ(gu)一般都试
几种方式来加载类Q如果你写了很多cd载器,你会发现你只是一ơ又一ơ在q个复杂的方
法中作一些修改而已。Java1.2UloadClass的默认实现包含了Lcȝ最普通的途径Q允?br>你覆盖findClassҎ(gu)QloadClass在适当的是否调用findClassҎ(gu)。这样做的好处是你不
需要覆盖loadClassQ你只需要覆盖findClassQ这样可以减工作量?br>新增Ҏ(gu): findClass
q个Ҏ(gu)被loadClass的默认实现调用。findClass的目标是包含所有类加蝲器特定的代码Q?br>而不需要重复这些代?比如在指定的Ҏ(gu)p|的时候调用系l类加蝲??br>新增Ҏ(gu): getSystemClassLoader
不论你是否覆盖方法findClass和loadClass, Ҏ(gu)getSystemClassLoader都可以直接访问系
l类加蝲?而不是通过findSystemClass间接的访??br>新增Ҏ(gu): getParent
Z把请求委托给父类加蝲器,通过q个Ҏ(gu)可以获得q个cd载器的父cd载器。当自定
义类加蝲器中的特定方法无法找到类的时候你可能把请求委托给父类加蝲器。类加蝲器的?br>cd载器包含创徏q个cd载器的代码?br>W六部分. 源代?br>CompilingClassLoader.java
以下是文件CompilingClassLoader.java内容
import java.io.*;
/*
CompilingClassLoader动态的~译Java源文件。它?class文g是否存在Q?class文g?br>否比源文仉旧?br>*/
public class CompilingClassLoader extends ClassLoader
{
// 指定一个文件名Q从盘d整个文g内容Q返回字节数l?br>private byte[] getBytes( String filename ) throws IOException {
// 获得文g大小?br>File file = new File( filename );
long len = file.length();
//创徏一个数l刚好可以存放文件的内容?br>byte raw[] = new byte[(int)len];
// 打开文g
FileInputStream fin = new FileInputStream( file );
// d所有内容,如果没法dQ表C发生了一个错误?br>int r = fin.read( raw );
if (r != len)
throw new IOException( "Can't read all, "+r+" != "+len );
// 别忘了关闭文件?br>fin.close();
// q回q个数组?br>return raw;
}
// 产生一个进E来~译指定的Java源文Ӟ制定文g参数.如果~译成功q回trueQ否?
// q回false?br>private boolean compile( String javaFile ) throws IOException {
// 昄当前q度
System.out.println( "CCL: Compiling "+javaFile+"..." );
// 启动~译?br>Process p = Runtime.getRuntime().exec( "javac "+javaFile );
// {待~译l束
try {
p.waitFor();
} catch( InterruptedException ie ) { System.out.println( ie ); }
// 查返回码Q看~译是否出错?br>int ret = p.exitValue();
// q回~译是否成功?br>return ret==0;
}
// cd载器的核心代?-加蝲cd需要的时候自动编译源文g?br>public Class loadClass( String name, boolean resolve )
throws ClassNotFoundException {
//我们的目的是获得一个类对象?br>Class clas = null;
// 首先Q检查是否已l出理过q个cR?br>clas = findLoadedClass( name );
//System.out.println( "findLoadedClass: "+clas );
// 通过cd获得路径?比如Qjava.lang.Object => java/lang/Object
String fileStub = name.replace( '.', '/' );
// 构徏指向源文件和cL件的对象?br>String javaFilename = fileStub+".java";
String classFilename = fileStub+".class";
File javaFile = new File( javaFilename );
File classFile = new File( classFilename );
//System.out.println( "j "+javaFile.lastModified()+" c "
//+classFile.lastModified() );
// 首先Q判断是否需要编译。如果源文g存在而类文g不存在,或者都存在Q但是源文g
// 较新Q说明需要编译?br>if (javaFile.exists() &&(!classFile.exists() ||
javaFile.lastModified() > classFile.lastModified())) {
try {
// ~译Q如果编译失败,我们必须声明p|原因Q仅仅用陈旧的cL不够的)?br>if (!compile( javaFilename ) || !classFile.exists()) {
throw new ClassNotFoundException( "Compile failed: "+javaFilename );
}
} catch( IOException ie ) {
// 可能~译时出现IO错误?br>throw new ClassNotFoundException( ie.toString() );
}
}
// 保已经正确~译或者不需要编译,我们开始加载原始字节?br>try {
// d字节?br>byte raw[] = getBytes( classFilename );
// 转化为类对象
clas = defineClass( name, raw, 0, raw.length );
} catch( IOException ie ) {
// q里q不表示p|Q可能我们处理的cd本地cd中,如java.lang.Object?br>}
//System.out.println( "defineClass: "+clas );
//可能在类库中Q以默认的方式加载?br>if (clas==null) {
clas = findSystemClass( name );
}
//System.out.println( "findSystemClass: "+clas );
// 如果参数resolve为trueQ根据需要解释类?br>if (resolve && clas != null)
resolveClass( clas );
// 如果q没有获得类Q说明出错了?br>if (clas == null)
throw new ClassNotFoundException( name );
// 否则Q返回这个类对象?br>return clas;
}
}
CCRun.java
一下是CCRun.java文g
import java.lang.reflect.*;
/*
CCLRun通过CompilingClassLoader加蝲cLq行E序?br>*/
public class CCLRun
{
static public void main( String args[] ) throws Exception {
// W一个参数指定用戯q行的主函数cR?br>String progClass = args[0];
// 接下来的参数是传l这个主函数cȝ参数?br>String progArgs[] = new String[args.length-1];
System.arraycopy( args, 1, progArgs, 0, progArgs.length );
// 创徏CompilingClassLoader
CompilingClassLoader ccl = new CompilingClassLoader();
// 通过CCL加蝲d数类?br>Class clas = ccl.loadClass( progClass );
// 利用反射调用它的d数和传递参数?br>// 产生一个代表主函数的参数类型的cd象?br>Class mainArgType[] = { (new String[0]).getClass() };
// 在类中找到标准的d数?br>Method main = clas.getMethod( "main", mainArgType );
// 创徏参数列表 -在这里,是一个字W串数组?br>Object argsArray[] = { progArgs };
// 调用d数?br>main.invoke( null, argsArray );
}
}
Foo.java
以下是文件Foo.java内容
public class Foo
{
static public void main( String args[] ) throws Exception {
System.out.println( "foo! "+args[0]+" "+args[1] );
new Bar( args[0], args[1] );
}
}
Bar.java
以下是文件Bar.java内容
import baz.*;
public class Bar
{
public Bar( String a, String b ) {
System.out.println( "bar! "+a+" "+b );
new Baz( a, b );
try {
Class booClass = Class.forName( "Boo" );
Object boo = booClass.newInstance();
} catch( Exception e ) {
e.printStackTrace();
}
}
}
baz/Baz.java
以下是文件baz/Baz.java内容
package baz;
public class Baz
{
public Baz( String a, String b ) {
System.out.println( "baz! "+a+" "+b );
}
}
Boo.java
以下是文件Boo.java内容
public class Boo
{
public Boo() {
System.out.println( "Boo!" );
}
}
W七部分. ȝ
ȝ
通过本文你是否意识到Q创定义cd载器可以让你深入到Java虚拟机的内部。你可以?br>M资源加蝲cLӞ或者动态的生成它,q样你就可以通过扩展q些功能做很多你感兴?br>的事Q还能完成一些强大的功能?br>关于ClassLoader的其它话?br>像本文开头说的,自定义类加蝲器在Java嵌入式浏览器和小应用E序览器中L重要?br>作用。下面给出类加蝲器的其它功能?br>* 安全Q?自定义的cd载器可以在把q个cMlJava虚拟Z前检查它是否有正的数字
{֐。你也可以自己创Z?沙箱"来阻止对某些Ҏ(gu)的调用,q是通过查源代码Q阻?br>该类Ҏ(gu)׃外的操作来实现的?br>* 加密Q通过自定义类加蝲器可以动态的解码Q所有你的类文g无法通过反编译被查看?br>代码。用户需要密码才能运行程序,q个密码用来对代码解密?br>* 存Q你是否需要将你的代码以某U格式或者压~Ş式发布吗Q自定义ClassLoader可以
从你惌的Q何资源中生成字节码文件?br>* 自提取程序:可以把整个应用程序编译到一个可执行的类文g中,q个文g包括压羃q或
者加密过的数据,有了内部cd载器Q当E序q行的时候,他把自己解包到内?不需要事
前安装?br>* 动态生成:可以动态的生成那些被引用的c?整个E序需要用的类都可以动态的生成然后
交给Java虚拟机?br>

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=94763



久城 2007-04-08 10:11 发表评论
]]>
վ֩ģ壺 ӰԺ߹ۿ| ŮƵ| aƵapp| ۺľƷ| ޾Ʒѹۿ| ޳˵Ӱ߹ۿ| 3344ѲŹۿƵ| þۺɫHEZYO| 99reƵƷȫ| ޾Ʒþþþþ | AVþWWW| ޵һվ| Ƭ߹ۿ| ձɫڹۿ| ޹˱ɫ| ¸߳60Ƶ| רר| ˳Ƭ߹ۿ| žžŹƷƵ| ĻƷһ| Ƭѿ| Ƶ߲| Ʒ69׽߹ۿ| ŮƷĻ| aëƬ߹ۿ| Ѳһ| ۺþþ| ҹƵ| ý61| 78˾ƷӰ߲պƷӰһ | ƵƬaaëƬ| ˾ƷۺƵ| ޹һ˾þþƷ| ƷԴѹۿ| ɫĻ߹ۿ| Ʒ޳ɦɦ߹ۿ | ҹþþƷ| ۺɫ| AVɫ| ޵Ƶѹۿ1000| պһ|