FilterInputStream和FilteOutputStream分别是过滤输入流和过滤输出流,他们的作用是为基础流提供一些额外的功能.拿FilterInputStream来说,常见的子类有DataInputStream,BufferedInputStream以及PushBackInputStream等.其子类总结为:
FilterInputStream所有的子类都是为基础流输入提供了一些额外的功能,为什么不直接继承基础流,将基础流中的方法直进行"装饰".这里要说到一个装饰者模式和继承的区别.
装饰者模式,就是将原有的基础流进行"装饰",那么装饰后的方法要与原先被装饰的基础类要保持一致,也可以在对基础流进行扩展.而继承是继承父类的属性和方法,通过重写父类里面的方法也可以起到"装饰"作用.比如强化或者优化父类里面的一些方法.两者的区别是装饰者模式可以动态地扩展一个对象.给对象添加额外的功能.而且装饰者和被装饰者之间不会产生耦合.
先看一下继承,例如要实现DataInputStream的功能,我们需要继承每个基础输入流,而且基础输入流不仅仅是图中这些,还有FileInputStream所有子类以及InputStream子类等等类,都需要继承,那么这些类就会爆炸式的增长.而且类之间耦合性特别高.如果使用继承,那么IO流系统何其庞大.
那么装饰者模式存在意义就在此处,相比继承,没有这么多繁杂的类,而且类与类的之间的耦合性降低,具体做法就是将提出一个类FilterInputStream.而其子类就是各个功能的实现类.如果想要基础输入流要某个功能,那么就可以将对应的基础输入流传到对应的子类构造方法中.代码也是来源于生活,这个装饰者模式跟生活中很多实例相似,比如每家有可乐,要想喝冰可乐,怎么办.不是每家去买一个冰箱,而是大家凑钱买一个公共的冰箱,然后要想喝冰颗可乐,就直接放在公共的冰箱里面,就实现了"冰"这个功能(好吧这个例子有点牵强)
案例:现在要将FileInputStream实现一个功能,读取与机器无关的java类中Int类型.就可以直接将FileInputStream传入DataInputStream的有参构造方法中
代码如下:
public class FilterDemo {
public static void main(String[] args) throws Exception{
DataOutputStream dos = new DataOutputStream(new FileOutputStream("D:\\java.txt"));
dos.writeInt(1234567);
DataInputStream dis = new DataInputStream(new FileInputStream("D:\\java.txt"));
System.out.println(dis.readInt());
dis.close();
dos.close();
}
}
运行结果:
1234567
public class FilterInputStream extends InputStream {
protected volatile InputStream in;
//有参构造方法,传入基础输入流
protected FilterInputStream(InputStream in) {
this.in = in;
}
//读取一个字节
public int read() throws IOException {
return in.read();
}
//从输入流读取数据到字节数组b中
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
//从输入流中读取数据到b的off位置开始,len个字节.
public int read(byte b[], int off, int len) throws IOException {
return in.read(b, off, len);
}
//跳过n个字节
public long skip(long n) throws IOException {
return in.skip(n);
}
//从输入流中可读取的剩余字节数
public int available() throws IOException {
return in.available();
}
public void close() throws IOException {
in.close();
}
//在输入流当前标记
public synchronized void mark(int readlimit) {
in.mark(readlimit);
}
//将当前位置重置到标记的位置
public synchronized void reset() throws IOException {
in.reset();
}
//测试输入流是否支持标记
public boolean markSupported() {
return in.markSupported();
}
}
public class FilterOutputStream extends OutputStream {
protected OutputStream out;
//有参构造方法,传入基础输出流
public FilterOutputStream(OutputStream out) {
this.out = out;
}
//将b写到输出流
public void write(int b) throws IOException {
out.write(b);
}
//将字节数组b写到输出流中
public void write(byte b[]) throws IOException {
write(b, 0, b.length);
}
//将字节数组b中off开始,len个字节写到输出流中
public void write(byte b[], int off, int len) throws IOException {
if ((off | len | (b.length - (len + off)) | (off + len)) < 0)
throw new IndexOutOfBoundsException();
for (int i = 0 ; i < len ; i++) {
write(b[off + i]);
}
}
//刷新输出流
public void flush() throws IOException {
out.flush();
}
//刷新输出流,强制将已写入缓冲的流写出
@SuppressWarnings("try")
public void close() throws IOException {
try (OutputStream ostream = out) {
flush();
}
}
}