建构自己的java库.docx

上传人:b****7 文档编号:9001911 上传时间:2023-02-02 格式:DOCX 页数:11 大小:19.60KB
下载 相关 举报
建构自己的java库.docx_第1页
第1页 / 共11页
建构自己的java库.docx_第2页
第2页 / 共11页
建构自己的java库.docx_第3页
第3页 / 共11页
建构自己的java库.docx_第4页
第4页 / 共11页
建构自己的java库.docx_第5页
第5页 / 共11页
点击查看更多>>
下载资源
资源描述

建构自己的java库.docx

《建构自己的java库.docx》由会员分享,可在线阅读,更多相关《建构自己的java库.docx(11页珍藏版)》请在冰豆网上搜索。

建构自己的java库.docx

建构自己的java库

第一章:

教程提示

代码重用是计算机编程的一个神圣目标。

编写可轻松重用的代码是非常难的技术,但这种技术并非不可掌握。

在本教程中,您将会学到:

Java语言如何能帮助您建立一个好的、可重用的库好的库设计的一些主要原则用Java语言实现这些构思的最有效方法

为说明这些构思,我们将设计一个简单的库。

要成功使用本教程,需要基本了解Java编程,包括能够创建、编译和执行简单的命令行Java程序。

目标

学完本教程之后,您将:

知道代码重用的主要障碍了解应用于库设计思想的知识知道如何用Java语言实现这些构思可以设计一个精良的Java库,以用作将来项目的样本。

第二章:

库简介

什么是库

库就是一个可重用软件组件,它通过提供到执行某个编程任务的代码的访问,来节省开发人员的时间。

库有助于完成许多不同类型的任务。

库设计是比较难的。

使用已编写的算法并将它称作库,这当然很简单;然而要结构化此代码以使它能够适应其他人的程序,并且执行其设计时设定的任务,同时不干扰原始程序的操作,这就很难了。

大多数现代语言都尝试帮助程序员创建好的库,Java语言也不例外。

在本教程中,您将会学到Java语言如何能帮助您建立一个好的、可重用的库。

第三章:

设计问题之封装

什么是封装

库应该是一种紧凑的自适应单元,而不是一种功能和关系不明确的对象的松散集合。

使库变成自适应的操作被称作封装。

[编辑]

什么是包

Java语言为类文件级别封装提供了一个显式机制:

包。

包是一组存储在一个单独目录中的Java类;包有它自己的名称空间。

给一组类其自己的名称空间的优点是不必担心名称空间冲突。

在这个示例中,主类有一个相当普通的名称--Server。

如果我们最后遇到另一个库中同名的类,不要感到惊奇。

将类放到它自己的名称空间中可以解决由于名称引起的冲突。

在以后几屏中,我将说明如何将一个类放入包中。

[编辑]

包具有名称

每个包都有一个名称,这个名称由一组用点分隔的字符串组成,如java.lang或javax.swing.plaf.basic。

实际上,任何类的全名都包含了它的包名称,后面跟着它自己的名称,如java.lang.Object或javax.swing.plaf.basic.BasicMenuBarUI。

请注意,有一个特殊包称作缺省包。

如果没有将类放到某个特定包中,那么会假设这个类在缺省包中。

[编辑]

包名称对应于目录

每个包都直接映射到文件系统中的一个子目录。

这种对应关系让Java虚拟机(JVM)可以在运行时找到类。

通过将点替换成"/"(或者操作系统用于分隔目录名的符号),可以将包名称转换成子目录路径。

例如,java.lang.Object存储在文件java/lang/Object.java中。

缺省包中的类被放置在当前目录中。

[编辑]

类声明了它们的包

为确保类在正确的包和正确的目录中,类必须声明它所在的包。

声明如下:

//Server.java

packagemylib;

publicclassServerimplementsRunnable{

//...

其它类可以导入包

如果要使用另一个包中的类,可以利用其全名来引用它,如mylib.Server。

例如:

mylib.Serverserver=newmylib.Server(portNum);

输入类的完整包名称可能很麻烦,因此可以使用快捷方式,按以下方式导入包:

importmylib.*;

//...

Serverserver=newServer(portNum);

还可以导入单个类:

importmylib.Server;

//...

Serverserver=newServer(portNum);

选择公有类

Java语言还可以让您决定在包外部可以看见包中的哪些类。

公有类可以被任何其它包中的代码访问,而私有类只能在其自己的包中使用。

只应该使那些需要人们直接使用的类成为公有类。

为公有类设计接口需要比为私有类设计接口更小心,因为必须精心设计公有类的接口,以使用户可以清楚地了解这个接口。

私有类则不必有一个清楚的接口。

要使类成为公有类,需要在类声明的第一行中使用public关键字:

//Server.java

packagemylib;

importjava.io.*;import.*;

publicclassServerimplementsRunnable{

要使类成为私有类,只要去掉public关键字。

在Server示例中,在称为Reporter的相同包中有一个私有类,它定期报告Server对象的情况。

以下就是它的声明:

//Reporter.java

packagemylib;

classReporterimplementsRunnable{

[编辑]

封装总结

可以看到,Java语言提供了一些特别为定义代码边界而创建的功能。

通过将代码划分到各个包中,并将类定义成公有类或私有类,可以确切地决定当用户使用库时他们必须处理什么问题。

第四章:

设计问题之可扩展性

继承

封装定义了代码段周围的边界。

所有面向对象编程语言都提供了一种机制,以扩展代码段而不破坏这些边界。

在Java语言中,这个机制由继承提供。

[编辑]

通过继承定制

示例库中的主类称作Server。

如果查看这个类的源代码,就会发现这个类本身什么功能也没有。

主循环(在单独线程中运行)侦听入网连接。

当进入一个连接时,它就将这个连接转交给一个称作handleConnection()的方法,如下所示:

//subclassmustsupplyanimplementation

abstractpublicvoidhandleConnection(Sockets);

由于没有缺省实现,因此这个类被声明成abstract,这表示用户应提供实现。

EchoServer实现了这个方法:

//ThisiscalledbytheServerclasswhenaconnection

//comesin."in"and"out"comefromtheincomingsocket

//connection

publicvoidhandleConnection(Socketsocket){

try{

InputStreamin=socket.getInputStream();

OutputStreamout=socket.getOutputStream();

//justcopytheinputtotheoutput

while(true)

out.write(in.read());

}catch(IOExceptionie){

System.out.println(ie);

}

}

可以将这个过程看作是一种定制:

完成大部分工作的类(Server)还不完整;子类(EchoServer)通过添加方法handleConnection()的实现来完善它。

[编辑]

考虑特殊情况

应该事先考虑库的用户想要执行的定制类型。

前一个示例很明显--必须提供一种方法以使子类能够真正使用入网连接,否则程序不产生任何作用。

但如果没有事先考虑,那么其它一些定制可能不提供给您。

相反,这些定制将提供给用户,用户希望您会事先考虑到这些情况。

在样本库中,Server中有一个方法叫作cleanUp()。

这个方法由服务器的后台线程在退出之前调用。

基本服务器不需要在这个方法中执行任何操作,因此它是空的:

//Putanylast-minuteclean-upstuffinhere

protectedvoidcleanUp(){

}

注:

不要将这个方法声明成abstract,因为这会要求用户实现此方法,而在某些情况下,没有必要这样做。

第五章:

设计问题之调试信息

为什么要计划调试

假设:

您的库很完美。

用户只需要学习API和使用代码就可以了。

对吗?

错。

这种假设决不会(或者很少会)发生。

错误不可避免;调试必不可少。

某些情况下,用户会遇到问题,他们需要知道库中到底在发生什么。

错误可能是库本身引起的,也可能是用户的代码中的错误,而这个错误只有在库内部才会引发。

[编辑]

一小段文本有很大帮助

如果您的库附带了源代码,那么用户可能会考虑使用调试器,但不应该指望用户会那样做。

解决这个不可避免的问题的更好方法是将调试语句println()添加到代码中,以强迫每一段代码都报告它在做什么。

查看此信息通常可以帮助用户了解在什么位置出了错。

以下示例演示了这个技术。

用户的代码通过调用静态方法Server.setDebugStream(),能够安装PrintStream对象。

实现之后,调试信息将被发送到已提供的流。

//setthistoaprintstreamifyouwantdebuginfo

//senttoit;otherwise,leaveitnull

staticprivatePrintStreamdebugStream;

//callthistosendthedebuggingoutputsomewhere

staticpublicvoidsetDebugStream(PrintStreamps){

debugStream=ps;

}

然后可以通过调用debug()方法来打印库的调试信息:

//senddebuginfototheprintstream,ifthereisone

staticpublicvoiddebug(Strings){

if(debugStream!

=null)

debugStream.println(s);

}

第六章:

源代码

样本库

在结束之前,先看一下完整的源代码,它包括了EchoServer、mylib.Server和mylib.Reporter。

EchoServer

//$Id$

importjava.io.*;import.*;importmylib.*;

publicclassEchoServerextendsServer{

publicEchoServer(intport){

//Thesuperclassknowswhattodowiththeportnumber,we

//don'thavetocareaboutit

super(port);

}

//ThisiscalledbytheServerclasswhenaconnection

//comesin."in"and"out"comefromtheincomingsocket

//connection

publicvoidhandleConnection(Socketsocket){

try{

InputStreamin=socket.getInputStream();

OutputStreamout=socket.getOutputStream();

//justcopytheinputtotheoutput

while(true)

out.write(in.read());

}catch(IOExceptionie){

System.out.println(ie);

}

}

protectedvoidcleanUp(){

System.out.println("Cleaningup");

}

staticpublicvoidmain(Stringargs[])throwsException{

//Grabtheportnumberfromthecommand-line

intport=Integer.parseInt(args[0]);

//Havedebugginginfosenttostandarderrorstream

Server.setDebugStream(System.err);

//Createtheserver,andit'supandrunning

newEchoServer(port);

}

}

mylib.Server

//$Id$

packagemylib;

importjava.io.*;import.*;

abstractpublicclassServerimplementsRunnable{

//theportwe'llbelisteningon

privateintport;

//howmanyconnectionswe'vehandled

intnumConnections;

//theReporterthat'sreportingonthisServer

privateReporterreporter;

//setthistotruetotellthethreadtostopaccepting

//connections

privatebooleanmustQuit=false;

publicServer(intport){

//remembertheportnumbersothethreadcan

//listenonit

this.port=port;

//theconstructorstartsabackgroundthread

newThread(this).start();

//andstartareporter

reporter=newReporter(this);

}

//thisisourbackgroundthread

publicvoidrun(){

ServerSocketss=null;

try{

//getreadytolisten

ss=newServerSocket(port);

while(!

mustQuit){

//giveoutsomedebugginginfo

debug("Listeningon"+port);

//waitforanincomingconnection

Sockets=ss.accept();

//recordthatwegotanotherconnection

numConnections++;

//moredebugginginfo

debug("Gotconnectionon"+s);

//processtheconnection--thisisimplemented

//bythesubclass

handleConnection(s);

}

}catch(IOExceptionie){

debug(ie.toString());

}

debug("Shuttingdown"+ss);

cleanUp();

}

//thedefaultimplementationdoesnothing

abstractpublicvoidhandleConnection(Sockets);

//tellthethreadtostopacceptingconnections

publicvoidclose(){

mustQuit=true;

reporter.close();

}

//Putanylast-minuteclean-upstuffinhere

protectedvoidcleanUp(){

}

//everythingbelowprovidesasimpledebugsystemfor

//thispackage

//setthistoaprintstreamifyouwantdebuginfo

//senttoit;otherwise,leaveitnull

staticprivatePrintStreamdebugStream;

//wehavetwoversionsofthis...

staticpublicvoidsetDebugStream(PrintStreamps){

debugStream=ps;

}

//...justforconvenience

staticpublicvoidsetDebugStream(OutputStreamout){

debugStream=newPrintStream(out);

}

//senddebuginfototheprintstream,ifthereisone

staticpublicvoiddebug(Strings){

if(debugStream!

=null)

debugStream.println(s);

}

}

mylib.Reporter

//$Id$

packagemylib;

classReporterimplementsRunnable{

//theServerwearereportingon

privateServerserver;

//ourbackgroundthread

privateThreadthread;

//setthistotruetotellthethreadtostopaccepting

//connections

privatebooleanmustQuit=false;

Reporter(Serverserver){

this.server=server;

//createabackgroundthread

thread=newThread(this);

thread.start();

}

publicvoidrun(){

while(!

mustQuit){

//dothereporting

Server.debug("serverhashad"+server.numConnections+"connections");

//thenpauseawhile

try{

Thread.sleep(5000);

}catch(InterruptedExceptionie){}

}

}

//tellthebackgroundthreadtoquit

publicvoidclose(){

mustQuit=true;

}

}

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 农学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1