计算机软件毕业设计OA办公管理系统的设计与实现文献翻译_第1页
计算机软件毕业设计OA办公管理系统的设计与实现文献翻译_第2页
计算机软件毕业设计OA办公管理系统的设计与实现文献翻译_第3页
计算机软件毕业设计OA办公管理系统的设计与实现文献翻译_第4页
计算机软件毕业设计OA办公管理系统的设计与实现文献翻译_第5页
已阅读5页,还剩30页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、重庆理工大Java IO 系统摘要可将 Java 库的 IO 类分割为输入与输出两个部分,这一点在用Web 浏览器阅读联机 Java 类文档时便可知道。通过继承,从 InputStream (输入流)衍生的所有类都拥有名为 read() 的基OutputStream 衍生的所有类都拥有基本 方法 write() ,用于写入单个字节或者字节数组。然而,我们通常不会用到这些方法;它们之所本方法,用于读取单个字节或者字节数组。类似地,从以存在,是因为更复杂的类可以利用它们,以便提供一个更有用的接口。因此,我们很少用单个类创建自己的系统对象。一般情况下,我们都是将多个对象重叠在一起,提供自己期望的功能

2、。我们之所以感到 Java 的流库( Stre am Library )异常复杂,正是由于为了创建单独一个结果 流,却需要创建多个对象的缘故。很有必要按照功能对类进行分类。库的设计者首先决定与输入有关的所有类都从InputStream继承,而与输出有关的所有类都从 OutputStream 继承。InputStream 的类型InputStream 的作用是标志那些从不同起源地产生输入的类。这些起源地包括(每个都有一个相关的 InputStream 子类):(1) 字节数组(2) String 对象(3) 文件(4) “管道”,它的工作原理与现实生活中的管道类似:将一些东西置入一端,它们在 另

3、一端出来。(5) 一系列其他流,以便我们将其统一收集到单独一个流内。可用字节数组创建一个);一个文件;或者一个“管道”。除此以外,破坏器”类提供了一个基础类,它将属性或者有用FilterOutputStream 为的接口同输出流连接起来。(6) 其他起源地,如 Internet 连接等(将在本书后面的部分讲述)。除此以外, FilterInputStream 也属于 InputStream 的一种类型,用它可为“破坏器”类 提供一个基础类,以便将属性或者有用的接口同输入流连接到一起。OutputStream 的类型String ;假定我 们这一类别包括的类决定了我们的输入往何处去:一个字节数组

4、(但没有如果想要打开一个文件用于字符输入,我们可以使用以是我们的最终对象和进行读取的接口。一旦抵达文件末尾readLine)将返回 null ,所以可以1. 缓冲输入文件String 或 File 对象作为文件名的FileInputReader 。为了提高速度,我们希望对那个文件进行缓冲,那么我们将作为结果的引用readline ()方法,所以这传给一个 BufferedReader 构造器。由于 BufferedReader 也提供用它来终止 while 循环。readline ()已将它们删掉)。字符串 s2 用来累积文件的全部内容 ( 包括必须添加的换行符, 因为 它在程序的后面部分将会

5、用到。 最后, 调用 close ()关闭文件。 从技术上讲, 当运行 finalize)时就会调用 close () ,那么程序结束时也应该发生这种情况(无论垃圾回收器是否存在)。然而,这种行为的实现并不是一致的,因此唯一安全的做法就是为文件明确调用close ()。1b部分展示了怎样包装 System.in 来读取来自控制台的输入。 System.in 是一个 InputStream ,BufferedReader 需要的是 Reader 参数,因此引入 InputStream 来执行转换。2. 从内存输入这部分获取已包含文件全部内容的字符串 s2 ,并用它创建一个 StringReade

6、r 。然后 调用read ()每次读取一个字符,并把它发送到控制台。注意read ()是以int的形式返 回下一字节,因此必须强制转换为 char 才能正确打印。3. 格式化的内存输入如果要读取格式化数据,我们要用到 DataInputStream ,它是一个面向字节的 I/O 类(不是面 向字符的)。因此我们必须使用 InputStream 类而不是 Reader 类。当然,我们可以用InputStream 以字节的形式读取任何数据(例如一个文件),不过,在这里使用的是字符串。为 了将字符串转换为成适用于 ByteArrayInputStream 的字节数组, String 包含了一个可以实

7、现 此项工作的 getBytes ()方法。至此,我们就持有了一个可传递给 DataInputStream 的InputStream 。那么由于任何字节的available ()如果我们从 DataInputStream 用 readByte() 一次一个字节地来读取字符, 值都是合法的结果,因此返回值不能用来检测输入是否结束。相反,我们可以使用 方法查看还有多少可供存取的字符。4. 文件输出 生。当我们使用 DataOutputStream 时,写字符串并且让 DataInputStream 能够恢复它的唯一 可靠的做法就是使用 UTF-8 编码,在例子第五部分中是用 writeUTF( )

8、 和 readUTF( ) 来实现 的。 UTF-8 是 Unicode 的变体,后者把所有字符都存储成两个字节的形式。如果我们使用的只 是 ASCII 或者几乎都是 ASCII 字符(只占 7 位),这么做就显得极其浪费空间和带宽,所以这个例子也展示了如何向文件写入数据。首先,创建一个与指定文件连接的FileWriter 。实际上,我们通常会用 BufferedWriter将其包装起来用以缓冲输出(尝试移除此包装来感受到对性能的影响缓冲往往能显著地增加I/O 操作的性能) 。然后为了格式化把它转换 PrintWriter 。按照这种方式创建的数据文件可作为普通文本文件读取。当读入行时, 行号

9、就会增加。 注意并未用到 LineNumberInputStream ,因为这个类没有多大帮助,所以我们没必要用它。正如在此所见,记录我们自己的行号很微不足道。一旦读完数据流,readLine() 会返回 null 。我们可以看到要为 out1 显式 close() ,如果我们不为所有的输出文 件调用 close() ,就会发现缓冲区内容不会刷新清空,那么它们也就不完整。5. 存储和恢复数据PrintStream 可以对数据进行格式化,以便人们的阅读。但是为了使输出可供另一个流恢复的数据,我们必需用 DataOutputStream 写入数据,并用 DataInputStream 恢复数据。当

10、然,这些 流可以是任何形式,但在这里我们采用的是一个文件,并且对于读和写都进行了缓冲处理。注意DataOutputStream 和 DataInputStream 是面向字节的,因此要使用 InputStream 和OutputStreams 。如果我们使用 DataOutputStream 写入数据, Java 保证我们可以使用DataInputStream 准确地读取数据无论读和写数据的平台怎么不同。这一点具有不可思议的价值,因为我们都知道人们曾经花费了大量时间去处理平台相关的数据问题。只要两个平台上都有Java,这种问题就不会再发UTF-8 将 ASCII 字符编码成单一字节的形式, 而

11、非 ASCII 字符则编码成两到三个字节的形式。另外,字符串的长度存储在前两个字节中。但是,writeUTF() 和readUTF()使用的是适合于Java 的 UTF-8 变体(在 JDK 文档中有这些方法的详尽描述),因此如果我们用一个非 Java 程序读取用 writeUTF( )所写的字符串时,必须编写一些特殊代码 才能正确读取字符串。有了 writeUTF( ) and readUTF( ) ,我们就可以用 DataOutputStream 把 字符串和其他数据类型相混合,我们知道字符串完全可以作为Unicode 来存储,并且可以很容 易地使用 DataInputStream 来恢复

12、它。 writeDouble() 将 double 类型的数字存储到流中,并用 相应的 readDouble() 恢复它(对于其他的数据类型,也有类似方法用于读写)。但是为了保证 所有的读方法都能够正常工作,我们必须知道流中数据项所在的确切位置,因为极有可能将保存 的 double 数据作为一个简单的字节序列、 char 或其他格式读入。因此,我们必须要么为文件 中的数据采用固定的格式,要么将额外的信息保存到文件中,以便能够对其进行解析从而确定数 据的存放位置。6读写随机访问文件正如先前所指, RandomAccessFile 除了实现 DataInput 和 DataOutput 接口之外,

13、几 乎完全独立于 I/O 继承层次结构的其他部分。所以不能将其与 InputStream 及当作一OutputStream 子类的任何部分组合起来。尽管把一个 ByteArrayInputStream 个随机访问元素对待也具有实际意义,但是我们只能用 RandomAccessFile 打开文件。我 们必须假定 RandomAccessFile 已经被正确缓冲,因为我们不能为它添加这样的功能。可以自行选择的是第二个构造器参数:我们可指定以只读 ”(r )方式或 “读写”( rw )方式 打开一个 RandomAccessFile 文件。使用 RandomAccessFile ,类似于组合使用了D

14、ataInputStream 和 DataOutputStream (因为它实现了同等的接口)。另外,我们会看到 利用 seek() ,可以在文件中到处移动,并 修改文件中的某个值。通过 FilterInputStream 从 InputStream 里读入数据FilterInputStream类要完成两件全然不同的事情。其中,DataInputStream 允许我们读取不同的基本类型数据以及等等)。伴随对应的String 对象(所有方法都以 “ readDataOutputStream ,我们可通过数据”开头,比如 readByte() ,read Float() 流”将基本类型的数据从一个

15、地方搬到另一个地方。其他 FilterInputstream 类则在内部修改 InputStream 的行为方式 : 是否缓冲 , 是否保留他所读过 的行(允许我们查询行数或设置行数 ), 以及是否把单一字符推回输入流等等。最后两个类看起来更像是为了创建一个编译器(它们被添加进来可能是为了对”用java构建编译器”实验提供支持),因此我们在一般编程中不会用到它们。 我们几乎每次都要对输入进行缓冲不管我们是正在连 接的是什么 I/O 设备,所以 I/O 类库吧无缓冲输入 (而不是缓冲输入 )作为哦特殊情况 用)就显得更加合理了。( 或是方法调String 对象通过 FilterOutputStr

16、eam 向 OutputStream 里写入数据 与 DataInputStream 对应的是 DataOutputStream ,后者对各个基本数据类型以及进行格式化,并将其置入一个数据“流”中,以便任何机器上的读取它们。所有方法都以“ wirte ”开头,例如 writeByt e()DataInputStream等等。,writeFloat()都能正常地若想进行一些真正的格式化输出,比如输出到控制台,请使用PrintStream。利用它可以打印出所有基本数据类型以及 String 对象,并可采用一种易于查看的格式。这与 正好相反,后者的目标是将那些数据置入一个数据流中,以便DataOut

17、putStreamDataInputStream 能够方便地重新构造它们。 System.out 静态对象是一个 PrintStreamPrintStream 内两个重要的方法是 print() 和 println()。它们已进行了覆盖处理,可打印出所有数据类型。 print()和 println() 之间的差异是后者在操作完毕后会自动添加一个新行。BufferedOutputStream 向流内物理性地写入数据。属于一种“修改器” ,用于指示数据流使用缓冲技术,使自己不必每次都通常都应将它应用于文件处理和控制器IO。File 类File 类有一个欺骗性的名字通常会认为它对付的是一个文件,但实

18、情并非如此。它既代表一 个特定文件的名字,也代表目录内一系列文件的名字。若代表一个文件集,便可用list() 方法查询这个集,返回的是一个字串数组。之所以要返回一个数组,而非某个灵活的集合类,是因为元素的数量是固定的。而且若想得到一个不同的目录列表,只需创建一个不同的File 对象即可。事实上,“ FilePath ”(文件路径)似乎是一个更好的名字。目录列表器现在假设我们想观看一个目录列表。可用两种方式列出File 对象。若在不含自变量(参数)的情况下调用 list() ,会获得 File 对象包含的一个完整列表。然而, 就需要使用一个“目录过滤器” ,该类的作用是指出应如何选择若想对这个列

19、表进行某些限制,File 对象来完成显示。检查与创建目录File 类并不仅仅是对现有目录路径、文件或者文件组的一个表示。亦可用一个 File 对象新建 个目录,甚至创建一个完整的目录路径假如它尚不存在的话。亦可用它了解文件的属性(长度、上一次修改日期、读写属性等) ,检查一个 File 对象到底代表一个文件还是一个目录,以及删除一个文件等等。重导向标准 IOJava 1.1 在 System 类中添加了特殊的方法, 允许我们重新定向标准输入、 输出以及错误 此时要用到下述简单的静态方法调用:IO 流。setIn(InputStream) setOut(PrintStream) setErr(P

20、rintStream)如果突然要在屏幕上生成大量输出,而且滚动的速度快于人们的阅读速度,输出的重定向就显得特别有用。在一个命令行程序中,如果想重复测试一个特定的用户输入序列,输入的重定向也显得特别有价值。压缩Java I/O 类库中中也添加一个类, 用以支持对压缩格式的数据流的读写。 它们封装到现成的 中,以提供压缩功能。IO 类这些是从新的 Reader 和 Writer 类衍生出来的,而是属于 InputStream 和 OutputStream 构的一部分。这样做是因为压缩类库是按字节方式而不是字符方式处理的。所以有时不得不混合层次结使用两种类型的数据流(注意可用 InputStream

21、Reader 和 OutputStreamWriter 在不同的类型间方便地进行转换) 。Java 归档( jar )实用程序Zip 格式亦在 Java 1.1 的 JAR( Java ARchive )文件格式中得到了采用。这种文件格式的作用是 将一系列文件合并到单个压缩文件里, 就象 Zip 那样。然而,同 Java 中其他任何东西一样, JAR 文件是跨平台的,所以不必关心涉及具体平台的问题。除了可以包括声音和图像文件以外,也可以在其中包括类文件。涉及因特网应用时, JAR 文件显得特别有用。在JAR 文件之前, Web 浏览器必须重复多次请求 Web 服务器,以便下载完构成一个“程序片

22、”Applet )的所有文件。除此以外,每个文件都是未经压缩的。但在将所有这些文件合并到一个JAR 文件里以后,只需向远程服务器发出一次请求即可。同时,由于采用了压缩技术,所以可在更短的时间里获得全部数据。另外,JAR 文件里的每个入口(条目)都可以加上数字化签名(详情参考Java 用户文档)。对象序列化Object Serialization )。它面向那些实现了Serializable 接口的对象, 可将它们转换成一系列字节, 并可在以后完全恢复回原来的样子。 这一 过程亦可通过网络进行。这意味着序列化机制能自动补偿操作系统间的差异。换句话说,可以先Java 增添了一种有趣的特性,名为“对

23、象序列化”在 Windows 机器上创建一个对象,对其序列化,然后通过网络发给一台Unix 机器,然后在那里准确无误地重新“装配” 。不必关心数据在不同机器上如何表示,也不必关心字节的顺序或者其他任何细节。就其本身来说,对象的序列化是非常有趣的,因为利用它可以实现“有限持久化”。请记住“持久化”意味着对象的“生存时间”并不取决于程序是否正在执行它存在或“生存”于程序的每一次调用之间。通过序列化一个对象,将其写入磁盘,以后在程序重新调用时重新恢复那个对象,就能圆满实现一种“持久”效果。之所以称其为“有限”,是因为能用某种"Persistent”(持久)关键字简单地地定义一个对象,并让系

24、统自动照看其他所有细节问题(尽管将来可能成为现实)。相反,必须在自己的程序中明确地序列化和组装对象。语言里增加了对象序列化的概念后, 可提供对两种主要特性的支持。 Java 1.1 的“远程方法调用”RMI )使本来存在于其他机器的对象可以表现出好象就在本地机器上的行为。将消息发给远程对象时,需要通过对象序列化来传输参数和返回值。对象的序列化也是 Java Beans 必需的,后者由 Java 1.1 引入。使用一个Bean 时,它的状态信息通常在设计期间配置好。 程序启动以后, 这种状态信息必须保存下来,以便程序启动以后恢复;具体工作由对象序列化完成。对象的序列化处理非常简单,只需对象实现了

25、Serializable 接口即可(该接口仅是一个标记,没有方法) 。在 Java 1.1中,许多标准库类都发生了改变,以便能够序列化其中包括用于基本数据类型的全部封装器、所有集合类以及其他许多东西。 甚至 Class对象也可以序列化。对象,然后将其封装到 ObjectOutPutStream为序列化一个对象,首先要创建某些 OutPutStreamOutputStream 。对象内。此时,只需调用 writeObject() 即可完成对象的序列化,并将其发送给 相反的过程是将一个 InputStream 封装到 ObjectInputStream 内,然后调用 readObject() 。和

26、往常 一样,我们最后获得的是指向一个上溯造型 Object 的句柄,所以必须下溯造型,以便能够直接 设置。,而且能追踪对象内包含对象序列化特别“聪明”的一个地方是它不仅保存了对象的“全景图” 的所有句柄并保存那些对象;接着又能对每个对象内包含的句柄进行追踪;以此类推。我们有时 将这种情况称为“对象网” ,单个对象可与之建立连接。而且它还包含了对象的句柄数组以及成 员对象。若必须自行操纵一套对象序列化机制,那么在代码里追踪所有这些链接时可能会显得非 常麻烦。 在另一方面, 由于 Java 对象的序列化似乎找不出什么缺点, 所以请尽量不要自己动手, 让它用优化的算法自动维护整个对象网。序列化的控制

27、正如大家看到的那样,默认的序列化机制并不难操纵。然而,假若有特殊要求又该怎么办呢?我 们可能有特殊的安全问题,不希望对象的某一部分序列化;或者某一个子对象完全不必序列化, 因为对象恢复以后,那一部分需要重新创建。此时,通过实现 Externalizable 接口,用它代替 Serializable 接口,便可控制序列化的具体过程。这 个 Externalizable 接 口 扩 展 了 Serializable , 并 增 添 了 两 个 方 法 : writeExternal() 和 readExternal() 。在序列化和重新装配的过程中, 会自动调用这两个方法, 以便我们执行一些特殊

28、操作。接口摘要接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法。这种机制在编程语言中并不通用。例如,C+对这些概念只有间接的支持。在java中存在语言关键字这个事实表明人们认为这些思想是很重要的,以至于要提供对它们的支持。首先我讲学习抽象类 , 它是普通类与接口之间的一种中庸之道。 尽管构建具有某些为实现方法的类时 ,你的第一想法可能 是创建接口但是抽象类仍是用于此目的一种重要而必须的工具。因为你不可能总是使用纯接口。抽象类和抽象方法在书中的“乐器”的例子中,基类 Instrument 中的方法往往是“哑 (dummy) ”方法。若要调用这 些方法 ,就会出现一些错误。 这是因为

29、 Instrument 类的目的是为他的所有导出类创建一个通用接口。建立了通用接口的唯一理由是 ,不同的子类可以用不同的方式表示此接口。 通用接口建立起一种基Instrument 类作为抽象类 ,或简称抽象类。本形式 ,以此所有导出类的共同部分。另一种说法是将如果你只有一个像 Instrument 这样的抽象类,那么该类的对象几乎总是没有任何意义。当我们创建抽象类总是希望通过这个通用接口操纵一系列类。因此 ,Instrument 只是表示了一个接口 ,没有具体的实现内容 ;因此 , 创建一个 Instrument 对象是没有意义的,并且我们可能还想阻止使用者这样做。 通过让 Instrumen

30、t 中的所有方都产生错误 ,就可以是想这个目的。 但是这样做会将错误信息延迟到运行时才获得 ,并且需要在客户进行可靠 ,详尽的测试。所以最好是在编译时捕获这些问题。abstract void f();包含抽象方法的类兼做抽象类。如果一个类包含一个或多个抽象方法,该类必须被限定为抽象的。(否则 ,编译就会出错。 )如果一个抽象类不完整 ,那么当我们试图产生该类的对象时编译器会怎样处理呢?由于抽象类创建对象时不安全的 ,所以我们会从编译器那里得到一条出错信息。这样 ,编译器会确保 抽象类的纯粹性 ,我们不必担心会误用它。如果从一个抽象类继承,并想创建该新类的对象 ,那么就必须为基类中的所有抽象方法

31、提供方法定义。 如果不这样 (可以选择不做 ),那么导出类便也是抽象类 ,且编译器将会强制我们用 abstract 关键字来限定这个类。内部类可将一个类定义置入另一个类定义中。这就叫作“内部类”内部类是一种非常有用的特性,因为它允许你把它一些逻辑上相互联系的类进行分组,组织在一起,并可控制一个类在另一个类里的 “可见性”。然而, 我们必须认识到内部类与以前讲述的 “合成”方法存在着根本的区别,这一点很重要。在最初, 内部类看起来就像是一种代码隐藏机制: 将类至于其他类的内部。 但是, 你将会了解到,内部类远不止瑞,它了解外围类,并能预支通信;而且你用内部类写出的代码更加优雅而清晰,尽管并不总是

32、这样。最初,内部类可能是看起来有些奇怪,而且要花些时间才能在设计中轻松地使用它们。 对内部类的需要并不是特别明显的, 但是在描述完内部类的基本语法与设计语义自后,你就会应该觉得内部类的有益处显现了。链接到外部类迄今为止,我们见到的内部类好象仅仅是一种名字隐藏以及代码组织方案。尽管这些功能非常有用,但似乎并不特别引人注目。然而,我们还忽略了另一个重要的事实。创建自己的内部类时,那个类的对象同时拥有指向封装对象(这些对象封装或生成了内部类)的一个链接。所以它们能访问那个封装对象的成员必须取得任何资格。除此以外,内部类拥有对封装类所有元素的访问权限。方法和作用域中的内部类至此, 我们已基本理解了内部

33、类的典型用途。 对那些涉及内部类的代码, 通常表达的都是 “单纯”的内部类,非常简单,且极易理解。然而,内部类的设计非常全面,不可避免地会遇到它们的其他大量用法假若我们在一个方法甚至一个任意的作用域内创建内部类。有两方面的原因促使我们这样做:(1) 正如前面展示的那样,我们准备实现某种形式的接口,使自己能创建和返回一个句柄。(2) 要解决一个复杂的问题,并希望创建一个类,用来辅助自己的程序方案。同时不愿意把它公开。内部类标识符由于每个类都会生成一个 .class文件,用于容纳与如何创建这个类型的对象有关的所有信息种信息产生了一个名为 Class对象的元类) ,所以大家或许会猜到内部类也必须生成

34、相应的 .class 文件,用来容纳与它们的 Class 对象有关的信息。这些文件或类的名字遵守一种严格的形式:先是封装类的名字,再跟随一个$,再跟随内部类的名字。例如,由 InheritInner.java创建的 .class 文件包括:InheritInner.class WithInner$Inner.class WithInner.class如果内部类是匿名的,那么编译器会简单地生成数字,把它们作为内部类标识符使用。若内部类嵌套于其他内部类中,则它们的名字简单地追加在一个$以及外部类标识符的后面。这种生成内Java 编译器会根,可适应大多数场合的要求。由于它是部名称的方法除了非常简单和

35、直观以外,也非常“健壮”Java 的标准命名机制,所以产生的文件会自动具备“与平台无关”的能(注意据情况改变内部类,使其在不同的平台中能正常工作)o为什么要用内部类:控制框架到目前为止,大家已接触了对内部类的运作进行描述的大量语法与概念。但这些并不能真正说明 内部类存在的原因。为什么 Sun 要如此麻烦地在添加这样的一种基本语言特性呢? 一般来说,内部类继承自某个类或是想某个接口,内部类的代码操作创建他的外围类的对象。所 以可以认为内部类提供了某种进入其外围的窗口。内部类必须回答的一个问题是:如果只是需要一个对接口的引用,为什么不同果果外围类实现那 个接口呢?答案是: “如果能满足需求,那么就

36、应该这样做。 ”那么内部类实现一个接口语外围类 实现这个接口有什么区别?答案是:后者不是总能享用到接口带来的方便,有时需要用到接口的 实现,所以,使用内部类最吸引个人的原因是: 每个内部类都能独立的继承自一个 (接口的) 实现, 所以无论外围是否已经继承了某个 (接口的) 实现,对已内部类都是没有影响的。如果没有内部类提供的、可以继承多个具体的火抽象的类的能力,一些设计与编程问题就很难解 决。从这个角度看,内部类使得多重继承的解决方案就变得完整。接口解决了部分问题,二内部 类有效的实现了”多重继承“。也就是说,内部类允许继承多个非接口类型(译注:抽象类)迭代器任何容器都必须有方法可以将东西放进

37、去,然后有方法将东西取出来。毕竟,存放事物是容器最 基本的工作。对于 ArrayList , add() 是插入对象的方法,而 get() 是取出元素的方法之一。ArrayList 很灵活,可以随时选取任意元素,或使用不同的下标一次选取多个元素。如果你从更高层的角度思考,会发现这里有个缺点:要使用容器必须知道其中元素确切的类型。ArrayList ,但是后来考虑到起初看起来这没什么不好,但是考虑下面的情况:如果原本是使用 容器的特点,你想换用 Set ,应该怎么做?或者你打算写通用的代码,它只是使用容器,不知道 或不关心容器的类型,那么如何才能不重写代码就可以应用于不同类型的容器呢? 迭代器的

38、概念(也是一种设计模式)可以用来达成此目的。迭代器是一个对象,它的工作是遍历 并选择序列中的对象。 客户端程序员不关心序列底层的结构。 此外, 迭代器通常被称为 “轻量级” 对象:创建它的代价小。因此,经常可以见到对迭代器有些奇怪的限制。例如,某些迭代器只能单向移动。 Java 的 Iterator 就是迭代器受限制的例子,它只能用来:1. 使用方法 iterator() 要求容器返回一个 Iterator 。第一次调用 Iterator 的 next() 方法时,它返回序列的第一个元素。2. 使用 next() 获得序列中的下一个元素。3. 使用 hasNext() 检查序列中是否还有元素。

39、4. 使用 remove() 将上一次返回的元素从迭代器中移除。Iterator 能做的也就是这些了。 它是迭代器最简单的实现, 但是已经很有用了 (而且还有为 List设计的更强大的 ListIterator)。SetSet 不保存重复的元素 (至于如何判断元素相同则为复杂, 等会会看到)。如果你试图 将相同对象的多个实例添加到 Set 中,那么它就会阻止这种重复现象。 Set 中最常被使 用的是测试归属性,你可以很容易地询问某个对象是否在某个Set 中。正因为如此,查找就成为了 Set中最重要的操作,因此你通常都会选择一个HashSet的实现,专门对 快速查找进行优化。Set 拥有与 Co

40、llection 完全相同的接口, 所以和两种不同的 List 不同,它没有什么额外的功能。相反, Set 完全就是一个 Collection ,只是具有不同的行为(这是实例和多形性最理想的应用: 用于表达不同的行为) 。在这里,一个 Set 只允许每个对象存在一个实例(正如大家以后会看到 的那样,一个对象的“值”的构成是相当复杂的) 。Stac kStack有时也可以称为“后入先出”(LIFO)集合。换言之,我们在堆栈里最后“压入”的东西 将是以后第一个“弹出”的。和其他所有 Java 集合一样,我们压入和弹出的都是“对象” ,所以 必须对自己弹出的东西进行“造型” 。Map将对象映射到其他

41、对象的能力是一种解决编程问题的杀手锏。例如,考虑一个程序,他将用来检 查 Java 的 Random 类色随机性。理想状态下, Random 可以将产生理想的数字分布,但要想测试Map 可以很容易地解决该它,则需要生成大量的随机数,并对落入不通过范围的数字进行计数。问题。SortedMap使用 SortedMap ( TreeMap 是其唯一的实现) ,可以确保“键”处于排序状态,这使得它具有额 外的功能,这些功能由 SortedMap 接口中的下列方法提供:Comparator comparator( ):返回当前 Map 使用的 Comparator ,或者返回 null ,表示以自然方式

42、排序。Object firstKey()Object lastKey()SortedMap subMap(fromKey, toKey): 到 toKey (不包含)的“键”:返回 Map 中的第一个“键” 。:返回 Map 中的最末一个“键” 。生成此 Map 的子集,范围由从 fromKey (包含)确定。SortedMap headMap(toKey): 所有“键值对”组成。生成此Map 的子集,由“键”小于 toKey 的SortedMap tailMap(fromKey): fromKey 的所有“键值对”组成。生成此Map 的子集,由“键”大于或等于LinkedHashMap为了提

43、高速度, LinkedHashMap 散列化所有的元素,但是在遍历“键值对”时,却又以元素的插入顺序返回“键值对” (printInO 会迭代遍历 Map,因此你可以看到遍历的结果) 。此外,可以 在构造器中设定LinkedHashMap,使之采用基于访问的“最近最少使用”(LRU算法,于是没有 被访问过的(可被看作需要删除的)元素就会出现在队列的前面。对于需要定期按顺序清除元素 以节省空间的程序来说,此功能使得程序很容易得以实现。HashMap 的性能因子要理解这个问题,必须先解释一些术语:容量( Capacity ):散列表中桶的数量。 初始化容量( Initial eapaeity ):

44、创建散列表时桶的数量。 HashMap 和 HashSet 都允许你 在构造器中指定初始化容量。尺寸( Size ):当前散列表中记录的数量。负载因子( Load faetor ):等于“ size/eapaeity ”。 负载因子为 0 ,表示空的散列表, 0.5表示半满的散列表,依此类推。轻负载的散列表具有冲突少、适宜插入与查询的特点(但是使用迭代器遍历会变慢)。HashMap与HashSet的构造器允许你指定负载因子。这意味着,当负载达到指定值时,容器会自动成倍的增加容量(桶rehashing )。的数量),并将原有的对象重新分配,存入新的桶内(这称为“重散列”WeakHashMap容器

45、类中有一种特殊的Map:WeakHashMa,p 它被用来保存 WeakReferenee 。它使得“规范映射”(eanoniealized mappings) 更易于使用。在这种映射中,每个“值”只保存一份实例以节省存储 空间。当程序需要那个“值”的时候,便在映射中查询现有的对象,然后使用它(而不是重新再 创建)。可将“值”作为“规范映射”的一部分,一同初始化,不过通常是在需要的时候才生成值”。这是一种节约存储空间的技术,因为 WeakHashMap 允许垃圾回收器自动清理“键”和“值” ,所 以它显得十分便利。对于向 WeakHashMap 添加“键”和“值”的操作,则没有什么特殊要求。W

46、eakHashMap会自动使用 WeakReferenee 包装它们。Java I/O systemQuiekviewInput and outputProgramming language I/O libraries often use the abstraetion of a stream, whieh represents any data souree or sink as an objeet eapable of produeing or reeeiving pieees of data. The stream hides the details of what happens to

47、the data inside the aetual I/O deviee. The Java library elasses for I/O are divided by input and output, as you ean see by looking at the elass hierarehy in the JDK doeumentation. Through inheritanee, everything derived from the InputStream or Reader elasses has basie methods ealled read( )for readi

48、ng a single byte or an array of bytes. Likewise, everything derived from OutputStream orWriter classes has basic methods called write( ) for writing a single byte or an array of bytes. However, you won't generally use these methods;they exist so that other classes can use them these other classe

49、s provide a more usefulinterface. Thus, you ' ll rarely create your stream object by using a single class, but instead will layer multiple objects together to provide your desired functionality (this is theDecorator design pattern, as you shall see in this section). The fact that you create more

50、 thanone object to produce a single stream is the primary reason that Java ' s I/O library is confusing.It' s helpful to categorize the classes by their functionality. In Java l.o, the library designers started by deciding that all classes that had anything to do with input would be inherite

51、d from InputStream, and all classes that were associated with output would be inherited from OutputStream.Types of InputStreamInputStream' s job is to represent classes that produce input from different sources. Thesesources can be:1.An array of bytes.2.A String obj ect.3.A file.4.A "pipe,&

52、quot; which works like a physical pipe: You put things in at one end and they comeout the other.5. A sequence of other streams, so you can collect them together into a single stream.6. Other sources, such as an Internetconnection. (This is covered in Thinking in Enterprise Java, available at www.Min

53、dV.) Each of these has an associated subclass of InputStream. In addition, the filterInputStream is also a type of InputStream, to provide a base class for "decorator" classes that attach attributes or useful interfaces to input streams.1. Buffered input fileTo open a file for character in

54、put, you use a FileInputReader with aString or a File object as the file name. For speed, you ' llwant that file tobe buffered so you give the resulting reference to the constructor for aBufferedReader. Since BufferedReader also provides thereadLine( ) method, this is your final object and the i

55、nterface you readfrom. When you reach the end of the file, readLine( ) returns null sothat is used to break out of the while loop.The String s2 is used to accumulate the entire contents of the file(including newlines that must be added since readLine( ) strips themoff). s2 is then used in the later

56、portions of this program. Finally, close( )is called to close the file. Technically, close( ) will be called whenfinalize( ) runs, and this is supposed to happen (whether or not garbagecollection occurs) as the program exits. However, this has beeninconsistently implemented, so the only safe approach is to explicitly callclose( ) for files.Section 1b shows how you can wrap System.in for reading console input.System.in is an InputSt

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论