Java IO : 流,以及适配器模式的应用
适配器其实是分为对象适配器和类适配器两种,两种的工作原理不太一样。
对象适配器是使用组合的方法,在Adapter中会保留一个原对象(Adaptee)的引用,适配器的实现就是讲Target中的方法委派给Adaptee对象来做,用Adaptee中的方法实现Target中的方法。
这种类型的好处就是,Adpater只需要实现Target中的方法就好了。
与对象适配器不同的是,类适配器是通过类的继承来实现的。Adpater直接继承了Target和Adaptee中的所有方法,并进行改写,从而实现了Target中的方法。
以上摘自 http://design-patterns.readthedocs.io/zh_CN/latest/structural_patterns/adapter.html
以ByteArrayInputStream为例,ByteArrayInputStream是一个基于对象的适配器,如下所示,
publicclass ByteArrayInputStream extends InputStream { /** * An array of bytes that was provided * by the creator of the stream. */ protected byte buf[]; /** * The index of the next character to read from the input stream buffer. */ protected int pos; protected int mark = 0; protected int count; public ByteArrayInputStream(byte buf[]) { this.buf = buf; this.pos = 0; this.count = buf.length; } public ByteArrayInputStream(byte buf[], int offset, int length) { this.buf = buf; this.pos = offset; this.count = Math.min(offset + length, buf.length); this.mark = offset; } public synchronized int read() { return (pos < count) ? (buf[pos++] & 0xff) : -1; } public synchronized int read(byte b[], int off, int len) { if (b == null) { throw new NullPointerException(); } else if (off < 0 || len < 0 || len > b.length - off) { throw new IndexOutOfBoundsException(); } if (pos >= count) { return -1; } int avail = count - pos; if (len > avail) { len = avail; } if (len <= 0) { return 0; } System.arraycopy(buf, pos, b, off, len); pos += len; return len; } public synchronized long skip(long n) { long k = count - pos; if (n < k) { k = n < 0 ? 0 : n; } pos += k; return k; } public synchronized int available() { return count - pos; } public boolean markSupported() { return true; } public void mark(int readAheadLimit) { mark = pos; } public synchronized void reset() { pos = mark; } public void close() throws IOException { }}
ByteArrayInputStream 内部维护了一个 byte buf[] 数组,通过继承 InputStream 的方法适配了对 buf[] 的读取。
StringBufferInputStream继承了InputStream类型,同时持有一个对 String 对象的引用,将 String 对象适配成InputStream类型的对象的适配器模式。
从byte流到char流的适配
在java语言的标准库 java I/O 里面,有一个InputStreamReader类叫做桥梁(bridge)类。InputStreamReader是从byte流到char流的一个桥梁,它读入byte数据并根据指定的编码将之翻译成char数据。 InputStreamReader虽然叫“桥梁”,但它不爽桥梁模式,是适配器模式的应用。 InputStreamReader InputStreamReader是从byte输入流到char输入流的一个适配器。下图所示就是InputStreamReader 的结构
/** * An InputStreamReader is a bridge from byte streams to character streams: It * reads bytes and decodes them into characters using a specified {@link * java.nio.charset.Charset charset
}. */public class InputStreamReader extends Reader { private final StreamDecoder sd; public InputStreamReader(InputStream in) { super(in); try { sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object } catch (UnsupportedEncodingException e) { // The default encoding should always be available throw new Error(e); } } public InputStreamReader(InputStream in, String charsetName) throws UnsupportedEncodingException { super(in); if (charsetName == null) throw new NullPointerException("charsetName"); sd = StreamDecoder.forInputStreamReader(in, this, charsetName); } public InputStreamReader(InputStream in, Charset cs) { super(in); if (cs == null) throw new NullPointerException("charset"); sd = StreamDecoder.forInputStreamReader(in, this, cs); } public InputStreamReader(InputStream in, CharsetDecoder dec) { super(in); if (dec == null) throw new NullPointerException("charset decoder"); sd = StreamDecoder.forInputStreamReader(in, this, dec); } public String getEncoding() { return sd.getEncoding(); } public int read() throws IOException { return sd.read(); } public int read(char cbuf[], int offset, int length) throws IOException { return sd.read(cbuf, offset, length); } public boolean ready() throws IOException { return sd.ready(); } public void close() throws IOException { sd.close(); }}
为了说明适配器类InputStreamReader是如何使用,请看下面例子。Echo类可以将控制台输入的任何字符串从新打印出来,源代码如下:
public class Echo { public static void main(String[] args) throws IOException { String line; InputStreamReader input = new InputStreamReader(System.in); System.out.println("Enter data and push enter:"); BufferedReader reader = new BufferedReader(input); line = reader.readLine(); System.out.println("Data entered :" + line); }}
可以看出,这个类接受一个类型为inputStream的System.in对象,将之适配成Reader类型,然后再使用
BufferedReader类“装饰”它,将缓冲功能加上去。这样一来,就可以使用BufferedReader对象的readerLine() 方法读入整行的输入数据,数据类型是String。参考:https://my.oschina.net/gao0516/blog/136103
============END============