list09

list09

ID:81525058

大小:87.50 KB

页数:19页

时间:2022-10-12

上传者:U-24289
list09_第1页
list09_第2页
list09_第3页
list09_第4页
list09_第5页
list09_第6页
list09_第7页
list09_第8页
list09_第9页
list09_第10页
资源描述:

《list09》由会员上传分享,免费在线阅读,更多相关内容在学术论文-天天文库

----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方第9章包和接口本章我们讲述Java最具有革新性的两个特点:包和接口。包(package)是类的容器,用来保存划分的类名空间。例如,一个包允许你创建一个名为List的类,你可以把它保存在你自己的包中而不用考虑和其他地方的某个名为List的类相冲突。包以分层方式保存并被明确的引入新的类定义。在前面的章节你已经了解了怎样在类中定义数据接口的方法。通过运用关键字interface,Java允许你充分抽象它实现的接口。用接口,你可以定义一系列的被一个类或多个类执行的方法。接口自己不定义任何实现。尽管它们与抽象类相似,接口有一个特殊的功能:类可以实现多个接口。与之相反,类只能继承一个超类(抽象类或其他)。包和接口是Java程序的两个基本组成。一般来说,Java源程序可以包含下面的四个内部部分的任何一个(或所有)。·单个接口声明(可选)·任意数目的引入语句(可选)·单个公共类声明(必须)·对包来说是私有的任意数目的类(可选)其中只有一个——单个公共类声明——在前面的程序中被用到。本章将探究剩下的三个部分。9.1包在前面的章节,每个例题类名从相同的名称空间获得。意思是说为避免名称冲突每个类都必须用惟一的名称。下面,没有管理名称空间的办法,你可能觉得不方便,因为每个单独的类都有描述性的名称。你还需要有确保你选用的类名是独特的且不和其他程序员选择的类名相冲突的方法(假想一小组程序员为用“Foobar”作类名而争斗。或者,设想整个Internet团体为谁最先为类取名为“Espresso”而争论)。感谢上帝,Java提供了把类名空间划分为更多易管理的块的机制。这种机制就是包。包既是命名机制也是可见度控制机制。你可以在包内定义类,而且在包外的代码不能访问该类。这使你的类相互之间有隐私,但不被其他世界所知。9.1.1定义包创建一个包是很简单的:只要包含一个package命令作为一个Java源文件的第一句就可以了。该文件中定义的任何类将属于指定的包。package语句定义了一个存储类的名字空间。如果你省略package----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方

1----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方语句,类名被输入一个默认的没有名称的包(这是为什么在以前你不用担心包的问题的原因)。尽管默认包对于短的例子程序很好用,但对于实际的应用程序它是不适当的。多数情况,需要为自己的代码定义一个包。下面是package声明的通用形式:packagepkg;这里,pkg是包名。例如,下面的声明创建了一个名为MyPackage的包。packageMyPackage;Java用文件系统目录来存储包。例如,任何你声明的MyPackage中的一部分的类的.class文件被存储在一个MyPackage目录中。记住这种情况是很重要的,目录名必须和包名严格匹配。多个文件可以包含相同package声明。package声明仅仅指定了文件中定义的文件属于哪一个包。它不拒绝其他文件的其他方法成为相同包的一部分。多数实际的包伸展到很多文件。你可以创建包层次。为做到这点,只要将每个包名与它的上层包名用点号“.”分隔开就可以了。一个多级包的声明的通用形式如下:packagepkg1[.pkg2[.pkg3]];包层次一定要在Java开发系统的文件系统中有所反映。例如,一个由下面语句定义的包:packagejava.awt.image;需要在你的UNIX、Windows或Macintosh文件系统的java/awt/image,java\awt\image或java:awt:image中分别保存。一定要仔细选用包名。你不能在没有对保存类的目录重命名的情况下重命名一个包。9.1.2理解类路径(CLASSPATH)在介绍运用包的例子之前,关于类路径环境变量的简单讨论是必要的。当包从访问控制和名称-空间-冲突中解决很多问题时,在编译和运行程序时它们导致某些古怪的难点。这是因为Java编译器考虑的特定位置作为包层次的根被类路径(CLASSPATH)控制。直到现在,你在同样的未命名的默认包中保存所有的类。这样做允许你仅仅通过在命令行键入类名编译源文件和运行Java解释器,并得到结果。这种情况下它还会工作是因为默认的当前工作目录(.)通常在类路径环境变量中为Java运行时间默认定义。然而,当有包参与时,事情就不这么简单。下面是原因。假设你在一个test包中创建了一个名为PackTest的类。因为你的目录结构必须与包相匹配,你创建一个名为test的目录并把PackTest.java装入该目录。然后使test成为当前目录并编译PackTest.java。这导致PackTest.class被存放在test目录下。当你试图运行PackTest时,java解释器报告一个与“不能发现PackTest类”相似的错误消息。这是因为该类现在被保存在test----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方

2----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方包中。不再能简单用PackTest来引用。必须通过列举包层次来引用该类。引用包层次时用逗号将包名隔开。该类现在必须叫做test.PackTest。然而,如果你试图用test.PackTest,你将仍然收到一个与“不能发现test/PackTest类”相似的出错消息。仍然收到错误消息的原因隐藏在类路径变量中。记住,类路径设置顶层类层次。问题在于在当前工作目录下不存在test子目录,因为你是工作在test目录本身。在这个问题上你有两个选择:改变目录到上一级然后用javatest.PackTest,或者在类路径环境变量增加你的开发类层次结构的顶层。然后可以用javatest.PackTest,Java将发现正确的.class文件。例如,如果你的源代码在目录C:\myjava下,那么设置类路径为:.;C:\myjava;C:\java\classes9.1.3一个简短的包的例子记住前面的讨论,试试下面简单的包://AsimplepackagepackageMyPack;classBalance{Stringname;doublebal;Balance(Stringn,doubleb){name=n;bal=b;}voidshow(){if(bal<0)System.out.print("-->");System.out.println(name+":$"+bal);}}classAccountBalance{publicstaticvoidmain(Stringargs[]){Balancecurrent[]=newBalance[3];current[0]=newBalance("K.J.Fielding",123.23);current[1]=newBalance("WillTell",157.02);current[2]=newBalance("TomJackson",-12.33);for(inti=0;i<3;i++)current[i].show();}}称该文件名为AccountBalance.java,把它存放在MyPack目录中。接着,编译文件。确信结果文件.class同样在MyPack目录中。然后用下面的命令行执行AccountBalance类:javaMyPack.AccountBalance----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方

3----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方记住,当你执行该命令时你必须在MyPack的上级目录,或者把类路径环境变量设置成合适的值。如上所述,AccountBalance现在是MyPack包的一部分。这意味着它不能自己执行。也就是说你不能用下面的命令行:javaAccountBalanceAccountBalance必须和它的包名一起使用。9.2访问保护前面已经学习了Java的访问控制机制的很多方面和它的访问说明符。例如,你已经知道一个类的private成员仅可以被该类的其他成员访问。包增加了访问控制的另一个维度。如你所看到的,Java提供很多级别的保护以使在类、子类和包中有完善的访问控制。类和包都是封装和容纳名称空间和变量及方法范围的方法。包就像盛装类和下级包的容器。类就像是数据和代码的容器。类是Java的最小的抽象单元。因为类和包的相互影响,Java将类成员的可见度分为四个种类:·相同包中的子类·相同包中的非子类·不同包中的子类·既不在相同包又不在相同子类中的类三个访问控制符,private、public和protected,提供了多种方法来产生这些种类所需访问的多个级别,表9-1总结了它们之间的相互作用。表9-1类成员访问Private成员默认的成员Protected成员Public成员同一类中可见是是是是同一个包中对子类可见否是是是同一个包中对非子类可见否是是是不同包中对子类可见否否是是不同的包中对非子类可见否否否是Java的访问控制机制看上去很复杂,我们可以按下面方法简化它。任何声明为public的内容可以被从任何地方访问。被声明成private的成员不能被该类外看到。如果一个成员不含有一个明确的访问说明,它对于子类或该包中的其他类是可见的。这是默认访问。如果你希望一个元素在当前包外可见,但仅仅是元素所在类的子类直接可见,把元素定义成protected。----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方

4----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方表9-1仅适用于类成员。一个类只可能有两个访问级别:默认的或是公共的。如果一个类声明成public,它可以被任何其他代码访问。如果该类默认访问控制符,它仅可以被相同包中的其他代码访问。9.2.1一个访问的例子下面的例子显示了访问修饰符的所有组合。该例有两个包和五个类。记住这两个不同包中的类需要被存储在以它们的包p1、p2命名的目录下。第一个包定义了三个类:Protection,Derived,和SamePackage。第一个类以合法的保护模式定义了四个int变量。变量n声明成默认受保护型。n_pri是private型,n_pro是protected,n_pub是public的。该例中每一个后来的类试图访问该类一个实例中的变量。根据访问权限不编译的行用单行注释//。在每个这样的行之前都是列举该级保护将允许访问的地点的注释。第二个类,Derived是同样包p1中Protection类的子类。这允许Derived访问Protection中的除n_pri以外的所有变量,因为它是private。第三个类,SamePackage,不是Protection的子类,但是是在相同的包中,也可以访问除n_pri以外的所有变量。下面是Protection.java文件:packagep1;publicclassProtection{intn=1;privateintn_pri=2;protectedintn_pro=3;publicintn_pub=4;publicProtection(){System.out.println("baseconstructor");System.out.println("n="+n);System.out.println("n_pri="+n_pri);System.out.println("n_pro="+n_pro);System.out.println("n_pub="+n_pub);}}下面是Derived.java文件:packagep1;classDerivedextendsProtection{Derived(){System.out.println("derivedconstructor");System.out.println("n="+n);//classonly//System.out.println("n_pri="+n_pri);System.out.println("n_pro="+n_pro);System.out.println("n_pub="+n_pub);----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方

5----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方}}下面是SamePackage.java文件:packagep1;classSamePackage{SamePackage(){Protectionp=newProtection();System.out.println("samepackageconstructor");System.out.println("n="+p.n);//classonly//System.out.println("n_pri="+p.n_pri);System.out.println("n_pro="+p.n_pro);System.out.println("n_pub="+p.n_pub);}}下面是另一个包p2的源代码。p2中定义的两个类重载了另两种受访问控制影响的情况。第一个类Protection2是p1.Protection的子类。这允许访问p1.Protection中除n_pri(因为它是private的)和n之外的所有变量,n是定义成默认保护型的。记住,默认型的只能允许类中或包中的代码访问。最后,OtherPackage类只访问了一个变量n_pub,它是定义成public型的。下面是Protection2.java文件:packagep2;classProtection2extendsp1.Protection{Protection2(){System.out.println("derivedotherpackageconstructor");//classorpackageonly//System.out.println("n="+n);//classonly//System.out.println("n_pri="+n_pri);System.out.println("n_pro="+n_pro);System.out.println("n_pub="+n_pub);}}下面是OtherPackage.java文件:packagep2;classOtherPackage{OtherPackage(){p1.Protectionp=newp1.Protection();System.out.println("otherpackage----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方

6----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方constructor");//classorpackageonly//System.out.println("n="+p.n);//classonly//System.out.println("n_pri="+p.n_pri);//class,subclassorpackageonly//System.out.println("n_pro="+p.n_pro);System.out.println("n_pub="+p.n_pub);}}如果你希望试试这两个包,下面是两个可以用的测试文件。包p1的测试文件如下://Demopackagep1.packagep1;//Instantiatethevariousclassesinp1.publicclassDemo{publicstaticvoidmain(Stringargs[]){Protectionob1=newProtection();Derivedob2=newDerived();SamePackageob3=newSamePackage();}}p2的测试文件如下://Demopackagep2.packagep2;//Instantiatethevariousclassesinp2.publicclassDemo{publicstaticvoidmain(Stringargs[]){Protection2ob1=newProtection2();OtherPackageob2=newOtherPackage();}}9.3引入包包的存在是划分不同类的好的机制,了解为什么所有Java内部的类都存在包中是很简单的。在未命名的默认包中是没有核心Java类的;所有的标准类都存储在相同的包中。既然包中的类必须包含它们的包名才能完全有效,为每个你想用的包写一个长的逗点分离的包路径名是枯燥的。因为这点,Java包含了import语句来引入特定的类甚至是整个包。一旦被引入,类可以被直呼其名的引用。import语句对于程序员是很方便的而且在技术上并不需要编写完整的Java程序。如果你在程序中将要引用若干个类,那么用import语句将会节省很多打字时间。在Java源程序文件中,import语句紧接着package语句(如果package----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方

7----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方语句存在),它存在于任何类定义之前,下面是import声明的通用形式:importpkg1[.pkg2].(classname|*);这里,pkg1是顶层包名,pkg2是在外部包中的用逗点(.)隔离的下级包名。除非是文件系统的限制,不存在对于包层次深度的实际限制。最后,你要么指定一个清楚的类名,要么指定一个星号(*),该星号表明Java编译器应该引入整个包。下面的代码段显示了所用的两种形式:importjava.util.Date;importjava.io.*;警告:星号形式可能会增加编译时间——特别是在你引入多个大包时。因为这个原因,明确的命名你想要用到的类而不是引入整个包是一个好的方法。然而,星号形式对运行时间性能和类的大小绝对没有影响。所有Java包含的标准Java类都存储在名为java的包中。基本语言功能被存储在java包中的java.lang包中。通常,你必须引入你所要用到的每个包或类,但是,既然Java在没有java.lang中的很多函数时是无用的,因此通过编译器为所有程序隐式引入java.lang是有必要的。这与下面的在你所有程序开头的一行是一样的:importjava.lang.*;如果在你用星号形式引用的两个不同包中存在具有相同类名的类,编译器将保持沉默,除非你试图运用其中的一个。这种情况下,你会得到一个编译时错误并且必须明确的命名指定包中的类。任何你用到类名的地方,你可以使用它的全名,全名包括它所有的包层次。例如,下面的程序使用了一个引入语句:importjava.util.*;classMyDateextendsDate{}没有import语句的例子如下:classMyDateextendsjava.util.Date{}如表9-1种所示,当一个包被引入,仅仅是该包中声明成public的项目可以在引入代码中对非子类可用。例如,如果你希望前面显示的MyPack包中的Balance类在MyPack外可以被独立的类运用,那么你需要声明它为public型,并把它存在自己的文件中,如下:packageMyPack;/*Now,theBalanceclass,itsconstructor,anditsshow()methodarepublic.Thismeansthattheycanbeusedbynon-subclasscodeoutsidetheir----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方

8----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方package.*/publicclassBalance{Stringname;doublebal;publicBalance(Stringn,doubleb){name=n;bal=b;}publicvoidshow(){if(bal<0)System.out.print("-->");System.out.println(name+":$"+bal);}}如你所见,Balance类现在是public。而且,它的构造函数和show( )方法也是public。这意味着它们可以被任何类型的MyPack包之外的代码访问。例如下面TestBalance引入了MyPack,那么它可以利用Balance类:importMyPack.*;classTestBalance{publicstaticvoidmain(Stringargs[]){/*BecauseBalanceispublic,youmayuseBalanceclassandcallitsconstructor.*/Balancetest=newBalance("J.J.Jaspers",99.88);test.show();//youmayalsocallshow()}}作为一个试验,从Balance类移去public修饰符,然后编译TestBalance,和分析得到的结论一样,将会产生错误。9.4接口(interface)用关键字interface,你可以从类的实现中抽象一个类的接口。也就是说,用interface,你可以指定一个类必须做什么,而不是规定它如何去做。接口在语句构成上与类相似,但是它们缺少实例变量,而且它们定义的方法是不含方法体的。实际上,这意味着你可以定义不用假设它们怎样实现的接口。一旦接口被定义,任何类成员可以实现一个接口。而且,一个类可以实现多个接口。要实现一个接口,接口定义的类必须创建完整的一套方法。然而,每个类都可以自由的决定它们自己实现的细节。通过提供interface关键字,Java允许你充分利用多态性的“一个接口,多个方法”。----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方

9----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方接口是为支持运行时动态方法解决而设计的。通常,为使一个方法可以在类间调用,两个类都必须出现在编译时间里,以便Java编译器可以检查以确保方法特殊是兼容的。这个需求导致了一个静态的不可扩展的类环境。在一个系统中不可避免会出现这类情况,函数在类层次中越堆越高以致该机制可以为越来越多的子类可用。接口的设计避免了这个问题。它们把方法或方法系列的定义从类层次中分开。因为接口是在和类不同的层次中,与类层次无关的类实现相同的接口是可行的。这是实现接口的真正原因所在。注意:接口增添了很多应用程序所需的功能。在一种语言例如C++中这些应用程序通常借助于多重继承来完成。9.4.1接口定义接口定义很像类定义。下面是一个接口的通用形式:accessinterfacename{      return-typemethod-name1(parameter-list);      return-typemethod-name2(parameter-list);      typefinal-varname1=value;      typefinal-varname2=value;      //...      return-typemethod-nameN(parameter-list);      typefinal-varnameN=value;}这里,access要么是public,要么就没有用修饰符。当没有访问修饰符时,则是默认访问范围,而接口是包中定义的惟一的可以用于其他成员的东西。当它声明为public时,则接口可以被任何代码使用。name是接口名,它可以是任何合法的标识符。注意定义的方法没有方法体。它们以参数列表后面的分号作为结束。它们本质上是抽象方法;在接口中指定的方法没有默认的实现。每个包含接口的类必需实现所有的方法。接口声明中可以声明变量。它们一般是final和static型的,意思是它们的值不能通过实现类而改变。它们还必须以常量值初始化。如果接口本身定义成public,所有方法和变量都是public的。下面是一个接口定义的例子。它声明了一个简单的接口,该接口包含一个带单个整型参数的callback( )方法。interfaceCallback{voidcallback(intparam);}9.4.2实现接口一旦接口被定义,一个或多个类可以实现该接口。为实现一个接口,在类定义中包括implements子句,然后创建接口定义的方法。一个包括implements子句的类的一般形式如下:accessclassclassname[extendssuperclass]                        [implementsinterface[,interface...]]{----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方

10----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方    //class-body}这里,access要么是public的,要么是没有修饰符的。如果一个类实现多个接口,这些接口被逗号分隔。如果一个类实现两个声明了同样方法的接口,那么相同的方法将被其中任一个接口客户使用。实现接口的方法必须声明成public。而且,实现方法的类型必须严格与接口定义中指定的类型相匹配。下面是一个小的实现Callback接口的例子程序:classClientimplementsCallback{//ImplementCallback'sinterfacepublicvoidcallback(intp){System.out.println("callbackcalledwith"+p);}}注意callback( )用public访问修饰符声明。注意:当实现一个接口方法时,它必须声明成public。类在实现接口时定义它自己的附加的成员,既是允许的,也是常见的。例如,下面的Client版本实现了callback( )方法,并且增加了nonIfaceMeth( )方法。classClientimplementsCallback{//ImplementCallback’sinterfacepublicvoidcallback(intp){System.out.println(“callbackcalledwith“+p);}voidnonIfaceMeth(){System.out.println(“Classesthatimplementinterfaces“+“mayalsodefineothermembers,too.”);}}通过接口引用实现接口你可以把变量定义成使用接口的对象引用而不是类的类型。任何实现了所声明接口的类的实例都可以被这样的一个变量引用。当你通过这些引用调用方法时,在实际引用接口的实例的基础上,方法被正确调用。这是接口的最显著特性之一。被执行的方法在运行时动态操作,允许在调用方法代码后创建类。调用代码在完全不知“调用者”的情况下可以通过接口来调度。这个过程和第8章描述的用超类引用来访问子类对象很相似。警告:因为Java中在运行时动态查询方法与通常的方法调用相比会有一个非常庞大的花费,所以在对性能要求高的代码中不应该随意的使用接口。下面的例子通过接口引用变量调用callback( )方法:classTestIface{publicstaticvoidmain(Stringargs[]){Callbackc=newClient();----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方

11----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方c.callback(42);}}该程序的输出如下:callbackcalledwith42注意变量c被定义成接口类型Callback,而且被一个Client实例赋值。尽管c可以用来访问Callback()方法,它不能访问Client类中的任何其他成员。一个接口引用变量仅仅知道被它的接口定义声明的方法。因此,c不能用来访问nonIfaceMeth( ),因为它是被Client定义的,而不是由Callback定义。前面的例子机械的显示了一个接口引用变量怎样访问一个实现对象,它没有说明这样的引用的多态功能。为演示这个用途,首先创建Callback的第二个实现,如下://AnotherimplementationofCallback.classAnotherClientimplementsCallback{//ImplementCallback'sinterfacepublicvoidcallback(intp){System.out.println("Anotherversionofcallback");System.out.println("psquaredis"+(p*p));}}现在,试试下面的类:classTestIface2{publicstaticvoidmain(Stringargs[]){Callbackc=newClient();AnotherClientob=newAnotherClient();c.callback(42);c=ob;//cnowreferstoAnotherClientobjectc.callback(42);}}程序输出如下:callbackcalledwith42Anotherversionofcallbackpsquaredis1764如你所见,被调用的callback( )的形式由在运行时c引用的对象类型决定。这是一个非常简单的例子,下面你将会看到另一个例子,它更实用。----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方

12----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方局部实现如果一个类包含一个接口但是不完全实现接口定义的方法,那么该类必须定义成abstract型。例如:abstractclassIncompleteimplementsCallback{inta,b;voidshow(){System.out.println(a+""+b);}//...}这里,类Incomplete没有实现callback( )方法,必须定义成抽象类。任何继承Incomplete的类都必须实现callback( )方法或者它自己定义成abstract类。9.4.3应用接口为理解接口的功能,让我们看一个更实际的例子。我们曾开发过一个名为Stack的类,该类实现了一个简单的固定大小的堆栈。然而,有很多方法可以实现堆栈。例如,堆栈的大小可以固定也可以不固定。堆栈还可以保存在数组、链表和二进制树中等。无论堆栈怎样实现,堆栈的接口保持不变。也就是说,push( )和pop( )方法定义了独立实现细节的堆栈的接口。因为堆栈的接口与它的实现是分离的,很容易定义堆栈接口,而不用管每个定义实现细节。让我们看下面的两个例子。首先,下面定义了一个整数堆栈接口,把它保存在一个IntStack.java文件中。该接口将被两个堆栈实现使用。//Defineanintegerstackinterface.interfaceIntStack{voidpush(intitem);//storeanitemintpop();//retrieveanitem}下面的程序创建了一个名为FixedStack的类,该类实现一个固定长度的整数堆栈://AnimplementationofIntStackthatusesfixedstorage.classFixedStackimplementsIntStack{privateintstck[];privateinttos;//allocateandinitializestackFixedStack(intsize){stck=newint[size];tos=-1;}//Pushanitemontothestackpublicvoidpush(intitem){if(tos==stck.length-1)//uselengthmemberSystem.out.println("Stackisfull.");else----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方

13----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方stck[++tos]=item;}//Popanitemfromthestackpublicintpop(){if(tos<0){System.out.println("Stackunderflow.");return0;}elsereturnstck[tos--];}}classIFTest{publicstaticvoidmain(Stringargs[]){FixedStackmystack1=newFixedStack(5);FixedStackmystack2=newFixedStack(8);//pushsomenumbersontothestackfor(inti=0;i<5;i++)mystack1.push(i);for(inti=0;i<8;i++)mystack2.push(i);//popthosenumbersoffthestackSystem.out.println("Stackinmystack1:");for(inti=0;i<5;i++)System.out.println(mystack1.pop());System.out.println("Stackinmystack2:");for(inti=0;i<8;i++)System.out.println(mystack2.pop());}}下面是IntStack的另一个实现。通过运用相同的接口定义IntStack创建了一个动态堆栈。这种实现中,每一个栈都以一个初始长度建造。如果初始化长度被超出,那么堆栈的大小将增加。每一次需要更多的空间,堆栈的大小成倍增长。//Implementa"growable"stack.classDynStackimplementsIntStack{privateintstck[];privateinttos;//allocateandinitializestackDynStack(intsize){stck=newint[size];tos=-1;}//Pushanitemontothestackpublicvoidpush(intitem){//ifstackisfull,allocatealargerstackif(tos==stck.length-1){----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方

14----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方inttemp[]=newint[stck.length*2];//doublesizefor(inti=0;i

15----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方for(inti=0;i<8;i++)mystack.push(i);mystack=ds;System.out.println("Valuesindynamicstack:");for(inti=0;i<12;i++)System.out.println(mystack.pop());mystack=fs;System.out.println("Valuesinfixedstack:");for(inti=0;i<8;i++)System.out.println(mystack.pop());}}该程序中,mystack是IntStack接口的一个引用。因此,当它引用ds时,它使用DynStack实现所定义的push( )和pop( )方法。当它引用fs时,它使用FixedStack定义的push( )和pop( )方法。已经解释过,这些决定是在运行时做出的。通过接口引用变量获得接口的多重实现是Java完成运行时多态的最有力的方法。9.4.4接口中的变量你可以使用接口来引入多个类的共享常量,这样做只需要简单的声明包含变量初始化想要的值的接口就可以了。如果你的一个类中包含那个接口(就是说当你实现了接口时),所有的这些变量名都将作为常量看待。这与在C/C++中用头文件来创建大量的#defined常量或const声明相似。如果接口不包含方法,那么任何包含这样接口的类实际并不实现什么。这就像类在类名字空间引入这些常量作final变量。下面的例子运用了这种技术来实现一个自动的“作决策者”:importjava.util.Random;interfaceSharedConstants{intNO=0;intYES=1;intMAYBE=2;intLATER=3;intSOON=4;intNEVER=5;}classQuestionimplementsSharedConstants{Randomrand=newRandom();intask(){intprob=(int)(100*rand.nextDouble());if(prob<30)returnNO;//30%elseif(prob<60)returnYES;//30%----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方

16----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方elseif(prob<75)returnLATER;//15%elseif(prob<98)returnSOON;//13%elsereturnNEVER;//2%}}classAskMeimplementsSharedConstants{staticvoidanswer(intresult){switch(result){caseNO:System.out.println("No");break;caseYES:System.out.println("Yes");break;caseMAYBE:System.out.println("Maybe");break;caseLATER:System.out.println("Later");break;caseSOON:System.out.println("Soon");break;caseNEVER:System.out.println("Never");break;}}publicstaticvoidmain(Stringargs[]){Questionq=newQuestion();answer(q.ask());answer(q.ask());answer(q.ask());answer(q.ask());}}注意该程序利用了Java的一个标准类:Random,该类提供伪随机数。它包含若干个方法。通过这些方法你可以获得你程序所需形式的随机数。该例中,用到了nextDouble( )方法。它返回0.0到1.0之间的随机数。该例子程序中,定义了两个类Question和AskMe。这两个类都实现了SharedConstants接口。该接口中定义了NO、YES、MAYBE、SOON、LATER和NEVER。每个类中,代码就像自己定义或继承了它们一样直接引用了这些变量。下面是该程序的输出示例。注意每次运行结果不同。----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方

17----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方LaterSoonNoYes9.4.5接口可以扩展接口可以通过运用关键字extends被其他接口继承。语法与继承类是一样的。当一个类实现一个继承了另一个接口的接口时,它必须实现接口继承链表中定义的所有方法。下面是一个例子://Oneinterfacecanextendanother.interfaceA{voidmeth1();voidmeth2();}//Bnowincludesmeth1()andmeth2()--itaddsmeth3().interfaceBextendsA{voidmeth3();}//ThisclassmustimplementallofAandBclassMyClassimplementsB{publicvoidmeth1(){System.out.println("Implementmeth1().");}publicvoidmeth2(){System.out.println("Implementmeth2().");}publicvoidmeth3(){System.out.println("Implementmeth3().");}}classIFExtend{publicstaticvoidmain(Stringarg[]){MyClassob=newMyClass();ob.meth1();ob.meth2();ob.meth3();}}作为一个实验你也许希望移走MyClass中meth1( )的实现。这将导致编译时错误。前面讲过,任何实现接口的类必须实现该接口定义的所有方法,包括从其他接口继承的任何方法。----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方

18----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方尽管我们在本书中包括的例子没有很频繁的用到包和接口,这两个工具是Java编程环境中的重要部分。实质上所有用Java编写的实际的程序和小应用程序都被包含在包中。一个数字也可能实现接口。因此,游刃有余的运用这些工具是非常有用的。----------专业最好文档,专业为你服务,急你所急,供你所需-------------文档下载最佳的地方

当前文档最多预览五页,下载文档查看全文

此文档下载收益归作者所有

当前文档最多预览五页,下载文档查看全文
温馨提示:
1. 部分包含数学公式或PPT动画的文件,查看预览时可能会显示错乱或异常,文件下载后无此问题,请放心下载。
2. 本文档由用户上传,版权归属用户,天天文库负责整理代发布。如果您对本文档版权有争议请及时联系客服。
3. 下载前请仔细阅读文档内容,确认文档内容符合您的需求后进行下载,若出现内容与标题不符可向本站投诉处理。
4. 下载文档时可能由于网络波动等原因无法下载或下载错误,付费完成后未能成功下载的用户请联系客服处理。
大家都在看
近期热门
相关文章
更多
相关标签
关闭