- 浏览: 234978 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
rq2_79:
Solr DataImportHandler增量方式导入时,有 ...
solr Data Import Request Handler -
rq2_79:
http://developer.51cto.com/col/ ...
JVM加载Class过程分析 -
chenfei3306:
感谢楼主的分析,现在对hql的解析有了大体的认识了
hibernate 的HQL源码分析 -
四个石头:
...
试用log4jdbc -
dongbiying:
真让人无耐呀!你觉得是不是jar的问题呀!
RetroGuard学习指南
一。引子(概括地介绍Java的IO)
无论是哪种编程语言,输入跟输出都是重要的一部分,Java也不例外,而且Java将输入/输出的功能和使用范畴做了很大的扩充。它采用了流的 机制来实现输入/输出,所谓流,就是数据的有序排列,而流可以是从某个源(称为流源或Source of Stream)出来,到某个目的地(称为流汇或Sink of Stream)去的。由流的方向,可以分成输入流和输出流,一个程序从输入流读取数据向输出流写数据。
如,一个程序可以用FileInputStream类从一个磁盘文件读取数据,如下图所示:
像FileInputStream这样的处理器叫做流处理器,它就像流的管道一样,从一个流源吸入某种类型的数据,并输出某种类型的数据。上面这种示意图叫做流的管道图。
同样道理,也可以用FileOutputStream类向一个磁盘文件写数据,如下图所示:
在实际应用这种机制并不没有太大的用处,程序需要写出地通常是非常结构化的信息,因此这些byte类型的数据实际上是一些数值,文字,源代码 等。Java的I/O库提供了一个称做链接(Chaining)的机制,可以将一个流处理器跟另一个流处理器首尾相接,以其中之一的输出为输入,形成一个 流管道的链接。
例如,DataInputStream流处理器可以把FileInputStream流对象的输出当作输入,将Byte类型的数据转换成Java的原始类型和String类型的数据。如下图所示:
类似地,向一个文件写入Byte类型的数据不是一个简单的过程。一个程序需要向一个文件里写入的数据往往都是结构化的,而Byte类型则是原始 类型。因此在写的时候必须经过转换。DataOutputStream流处理器提供了接收了原始数据类型和String数据类型,而这个流处理器的输出数 据则是Byte类型。也就是说DataOutputStream可以将源数据转换成Byte类型的数据,再输出来。
这样一来,就可以将DataOutputStream与FileOutputStream链接起来,这样程序就可以将原始数据类型和String类型的源数据写入这个链接好的双重管道里面,达到将结构化数据写到磁盘文件里面的目的,如下图所示:
这又是链接的所发挥的大作用。
流处理器所处理的流必定都有流源,而如果将流类所处理的流源分类的话,基本可以分成两大类:
第一 数组,String,File等,这一种叫原始流源。
第二 同样类型的流用做链接流类的流源,叫链接流源。
二 Java I/O库的设计原则
Java语言的I/O库是对各种常见的流源,流汇以及处理过程的抽象化。客户端的Java程序不必知道最终的流源,流汇是磁盘上的文件还是数组等;也不必关心数据是否经过缓冲的,可否按照行号读取等处理的细节。
书中提到了,对于第一次见到Java/IO库的人,无不因为这个库的庞杂而感到困惑;而对于熟悉这个库的人,而又常常为这个库的设计是否得当而争论不体。书的作者提出自己的意见,要理解Java I/O这个庞大而复杂的库,关键是要掌握两个对称性跟两个设计模式模式。
Java I/O库具有两个对称性,它们分别是:
1 输入-输出对称性,比如InputStream和OutputStream各自占据Byte流的输入与输出的两个平行的等级结构的根部。而Reader和Writer各自占据Char流的输入与输出的两个平行的等级结构的根部。
2 byte-char对称,InputStream和Reader的子类分别负责Byte和Char流的输入;OutputStream和Writer的子类分别负责Byte和Char流的输出,它们分别形成平行的等级结构。
Java I/O库的两个设计模式:
Java的I/O库总体设计是符合装饰者模式(Decorator)跟适配器模式(Adapter)的。如前所述,这个库中处理流的类叫做流 类。引子里所谈到的FileInputStream,FileOutputStream,DataInputStream及 DataOutputStream都是流处理器的例子。
1 装饰者模式:在由InputStream,OutputStream,Reader和Writer代表的等级结构内部,有一些流处理器可以 对另一些流处理器起到装饰作用,形成新的,具有改善了的功能的流处理器。装饰者模式是Java I/O库的整体设计模式。这样的一个原则是符合装饰者模式的,如下图所示:
2 适配器模式:在由InputStream,OutputStream,Reader和Writer代表的等级结构内部,有一些流处理器是对其它类型的流源的适配。这就是适配器模式的应用,如下图所示。
适配器模式应用到了原始流处理器的设计上面,构成了I/O库所有流处理器的起点。
JDK为程序员提供了大量的类库,而为了保持类库的可重用性,可扩展性和灵活性,其中使用到了大量的设计模式,本文将介绍JDK的I/O包中使用到的Decorator模式,并运用此模式,实现一个新的输出流类。
适配器类图如下:
在看源代码
Public class FileInputStream extends InputStream{
/* File Descriptor - handle to the open file */
private FileDescriptor fd;
public FileInputStream(FileDescriptor fdObj) {
SecurityManager security = System.getSecurityManager();
if (fdObj == null) {
throw new NullPointerException();
}
if (security != null) {
security.checkRead(fdObj);
}
fd = fdObj;
}
public FileInputStream(File file) throws FileNotFoundException {
String name = file.getPath();
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(name);
}
fd = new FileDescriptor();
open(name);
}
//其它代码
}
我的理解:
它继承了InputStrem类型,同时持有一个对FileDiscriptor的引用,是将一个FileDiscriptor对象适配成InputStrem类型的对象形式的适配器模式。
Decorator模式简介
Decorator模式又名包装器(Wrapper),它的主要用途在于给一个对象动态的添加一些额外的职责。与生成子类相比,它更具有灵活性。
有时候,我们需要为一个对象而不是整个类添加一些新的功能,比如,给一个文本区添加一个滚动条的功能。我们可以使用继承机制来实现这一功能,但 是这种方法不够灵活,我们无法控制文本区加滚动条的方式和时机。而且当文本区需要添加更多的功能时,比如边框等,需要创建新的类,而当需要组合使用这些功 能时无疑将会引起类的爆炸。
我们可以使用一种更为灵活的方法,就是把文本区嵌入到滚动条中。而这个滚动条的类就相当于对文本区的一个装饰。这个装饰(滚动条)必须与被装饰 的组件(文本区)继承自同一个接口,这样,用户就不必关心装饰的实现,因为这对他们来说是透明的。装饰会将用户的请求转发给相应的组件(即调用相关的方 法),并可能在转发的前后做一些额外的动作(如添加滚动条)。通过这种方法,我们可以根据组合对文本区嵌套不同的装饰,从而添加任意多的功能。这种动态的 对对象添加功能的方法不会引起类的爆炸,也具有了更多的灵活性。
以上的方法就是Decorator模式,它通过给对象添加装饰来动态的添加新的功能。如下是Decorator模式的UML图:
Component为组件和装饰的公共父类,它定义了子类必须实现的方法。
ConcreteComponent是一个具体的组件类,可以通过给它添加装饰来增加新的功能。
Decorator是所有装饰的公共父类,它定义了所有装饰必须实现的方法,同时,它还保存了一个对于Component的引用,以便将用户的请求转发给Component,并可能在转发请求前后执行一些附加的动作。
ConcreteDecoratorA和ConcreteDecoratorB是具体的装饰,可以使用它们来装饰具体的Component.
我的理解:
上图中的抽象链接流是一个Decorator,它不真正的装饰,它只提供接口,让它的子类去装饰。相当于上图中的具体链接流去装饰原始流。
JAVA IO包中的Decorator模式
JDK提供的java.io包中使用了Decorator模式来实现对各种输入输出流的封装。以下将以java.io.OutputStream及其子类为例,讨论一下Decorator模式在IO中的使用。
首先来看一段用来创建IO流的代码:
以下是代码片段:
try {
OutputStream out = new DataOutputStream(new FileOutputStream("test.txt"));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
这段代码对于使用过JAVA输入输出流的人来说再熟悉不过了,我们使用DataOutputStream封装了一个 FileOutputStream.这是一个典型的Decorator模式的使用,FileOutputStream相当于 Component,DataOutputStream就是一个Decorator.将代码改成如下,将会更容易理解:
以下是代码片段:
try {
OutputStream out = new FileOutputStream("test.txt");
out = new DataOutputStream(out);
} catch(FileNotFoundException e) {
e.printStatckTrace();
}
由于FileOutputStream和DataOutputStream有公共的父类OutputStream,因此对对象的装饰对于用户来说几乎是透明的。下面就来看看OutputStream及其子类是如何构成Decorator模式的:
OutputStream是一个抽象类,它是所有输出流的公共父类,其源代码如下:
以下是代码片段:
public abstract class OutputStream implements Closeable, Flushable {
public abstract void write(int b) throws IOException;
……
}
它定义了write(int b)的抽象方法。这相当于Decorator模式中的Component类。
ByteArrayOutputStream,FileOutputStream 和 PipedOutputStream 三个类都直接从OutputStream继承,以ByteArrayOutputStream为例:
以下是代码片段:
public class ByteArrayOutputStream extends OutputStream {
protected byte buf[];
protected int count;
public ByteArrayOutputStream() {
this(32);
}
public ByteArrayOutputStream(int size) {
if (size 〈 0) {
throw new IllegalArgumentException("Negative initial size: "
+ size);
}
buf = new byte[size];
}
public synchronized void write(int b) {
int newcount = count + 1;
if (newcount 〉 buf.length) {
byte newbuf[] = new byte[Math.max(buf.length 〈〈 1, newcount)];
System.arraycopy(buf, 0, newbuf, 0, count);
buf = newbuf;
}
buf[count] = (byte)b;
count = newcount;
}
……
}
它实现了OutputStream中的write(int b)方法,因此我们可以用来创建输出流的对象,并完成特定格式的输出。它相当于Decorator模式中的ConcreteComponent类。
接着来看一下FilterOutputStream,代码如下:
以下是代码片段:
public class FilterOutputStream extends OutputStream {
protected OutputStream out;
public FilterOutputStream(OutputStream out) {
this.out = out;
}
public void write(int b) throws IOException {
out.write(b);
}
……
}
同样,它也是从OutputStream继承。但是,它的构造函数很特别,需要传递一个OutputStream的引用给它,并且它将保存对此 对象的引用。而如果没有具体的OutputStream对象存在,我们将无法创建FilterOutputStream.由于out既可以是指向 FilterOutputStream类型的引用,也可以是指向ByteArrayOutputStream等具体输出流类的引用,因此使用多层嵌套的方 式,我们可以为ByteArrayOutputStream添加多种装饰。这个FilterOutputStream类相当于Decorator模式中的 Decorator类,它的write(int b)方法只是简单的调用了传入的流的write(int b)方法,而没有做更多的处理,因此它本质上没有对流进行装饰,所以继承它的子类必须覆盖此方法,以达到装饰的目的。
BufferedOutputStream 和 DataOutputStream是FilterOutputStream的两个子类,它们相当于Decorator模式中的 ConcreteDecorator,并对传入的输出流做了不同的装饰。以BufferedOutputStream类为例:
以下是代码片段:
public class BufferedOutputStream extends FilterOutputStream {
……
private void flushBuffer() throws IOException {
if (count 〉 0) {
out.write(buf, 0, count);
count = 0;
}
}
public synchronized void write(int b) throws IOException {
if (count 〉= buf.length) {
flushBuffer();
}
buf[count++] = (byte)b;
}
……
}
这个类提供了一个缓存机制,等到缓存的容量达到一定的字节数时才写入输出流。首先它继承了FilterOutputStream,并且覆盖了父 类的write(int b)方法,在调用输出流写出数据前都会检查缓存是否已满,如果未满,则不写。这样就实现了对输出流对象动态的添加新功能的目的。
下面,将使用Decorator模式,为IO写一个新的输出流。
自己写一个新的输出流
了解了OutputStream及其子类的结构原理后,我们可以写一个新的输出流,来添加新的功能。这部分中将给出一个新的输出流的例子,它将 过滤待输出语句中的空格符号。比如需要输出"java io OutputStream",则过滤后的输出为"javaioOutputStream".以下为SkipSpaceOutputStream类的代码:
以下是代码片段:
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* A new output stream, which will check the space character
* and won‘t write it to the output stream.
* @author Magic
*
*/
public class SkipSpaceOutputStream extends FilterOutputStream {
public SkipSpaceOutputStream(OutputStream out) {
super(out);
}
/**
* Rewrite the method in the parent class, and
* skip the space character.
*/
public void write(int b) throws IOException{
if(b!=‘ ’){
super.write(b);
}
}
}
它从FilterOutputStream继承,并且重写了它的write(int b)方法。在write(int b)方法中首先对输入字符进行了检查,如果不是空格,则输出。
以下是一个 测试程序:
以下是代码片段:
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Test the SkipSpaceOutputStream.
* @author Magic
*
*/
public class Test {
public static void main(String[] args){
byte[] buffer = new byte[1024];
/**
* Create input stream from the standard input.
*/
InputStream in = new BufferedInputStream(new DataInputStream(System.in));
/**
* write to the standard output.
*/
OutputStream out = new SkipSpaceOutputStream(new DataOutputStream(System.out));
try {
System.out.println("Please input your words: ");
int n = in.read(buffer,0,buffer.length);
for(int i=0;i〈n;i++){
out.write(buffer[i]);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
执行以上测试程序,将要求用户在console窗口中输入信息,程序将过滤掉信息中的空格,并将最后的结果输出到console窗口。比如:
以下是引用片段:
Please input your words:
a b c d e f
abcdef
总 结
在java.io包中,不仅OutputStream用到了Decorator设计模式,InputStream,Reader,Writer 等都用到了此模式。而作为一个灵活的,可扩展的类库,JDK中使用了大量的设计模式,比如在Swing包中的MVC模式,RMI中的Proxy模式等等。 对于JDK中模式的研究不仅能加深对于模式的理解,而且还有利于更透彻的了解类库的结构和组成。
发表评论
-
Java线程:线程状态的转换
2012-03-14 19:45 1164http://lavasoft.blog.51cto.co ... -
深入探索 高效的Java异常处理框架
2012-02-16 18:04 1239摘要:本文从Java异常最 ... -
spring ioc原理
2012-02-05 21:24 1196最近,买了本Spring入门书:spring In Actio ... -
JAVA集合小结
2012-02-05 15:03 681AVA集合小结 下面是我自己画的,关系画得没 ... -
JVM加载Class过程分析
2012-02-05 13:45 1288我们知道, JVM是通过调用一个 Class类得 ... -
在实践中使用Jstat监控gc情况
2011-11-10 15:49 891性能测试过程中,我们该如何监控java虚拟机内存的使用情况, ... -
java内存溢出类型
2011-08-26 16:09 643一、内存溢出类型 1、java.lang.OutOfMe ... -
Quartz
2009-12-18 11:02 784"0 0 12 * * ?" 每天中午12 ... -
Apache Commons Pool
2009-11-20 18:05 1871Apache Commons Pool高级配 ... -
几种开源Java Web容器线程池的实现方法简介
2007-11-27 15:49 1307http://tenyears.cn/index.php/20 ... -
Java 接口大全、面向接口编程、什么时候使用接口。选择Java接口还是抽象类
2007-11-23 11:17 983什么叫面向接口编程[作者:umlchina 转贴自:www.u ... -
比较分析Vector、ArrayList和hashtable hashmap数据结构
2007-11-19 13:48 1628线性表,链表,哈希表 ... -
Bean生成方法类
2007-10-12 13:38 1178java 代码 import java.bea ... -
RetroGuard学习指南
2007-09-28 13:28 39081.类包下载 http://www.retrologic.co ... -
JAVA对象序列化保存为XML文件的工具类
2007-09-13 10:04 2670java 代码 import java.bea ...
相关推荐
java IO教程,java IO教程,java IO教程,java IO教程java IO教程java IO教程java IO教程java IO教程,java IO教程java IO教程java IO教程java IO教程java IO教程,java IO教程,java IO教程,java IO教程,java IO...
Java教程之javaIO详解Java教程之javaIO详解Java教程之javaIO详解
以前学java时候看的马士兵老师的教程,老师讲的较快,有些不适应,自己做些笔记巩固练习,效果还不错,贴出来分析大家把,配图+示例。。。
IO流 javaio java 流
java io 结构图java io 结构图
深入分析javaIO的工作机制.doc
彻底明白Java的IO流
1、Java IO_NIO 2、Java+IO.pdf
java学习笔记1(java io/nio)设计模式
IO 简介,只看这篇,IO全部搞定,对于初学者来说,不可多得
java IO文档java IO文档java IO文档java IO文档java IO文档java IO文档
JAVA课件Java IO.ppt详细了解JAVA
javaIO流javaIO流
java io.pdf java io.pdf
第8章JavaIO第8章JavaIO第8章JavaIO
java io处理 方法java io处理 方法
java io 文件读写
java IO操作详细解释 清华大学java io专用教材
Java io流的总结
深入分析JavaIO的工作机制.doc