Java面试官:开发过程中

public int read() throws IOException {
return in.read();
}

public int read(byte b[]) throws IOException {
    return read(b, 0, b.length);
}

public int read(byte b[], int off, int len) throws IOException {
    return in.read(b, off, len);
}

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();
}

}


所以正如其名,FilterInputStream 就像是内部 InputStream 对象的一个过滤器一般,所有方法调用都需要经过一层包装方法的『过滤』才能到达内部对象。FilterInputStream 并没有逻辑实现,具体实现需要子类覆写相关方法实现。

比较有意思的实现有以下几个:

*   **BufferedInputStream**

    > BufferedInputStream 内部使用一个 buf 字节数组进行缓冲,覆写了 FilterInputStream 的全部方法实现一个带缓冲区的字节流类。在进行磁盘或网络IO时,原始的InputStream对数据读取的过程都是一个字节一个字节操作的,而BufferedInputStream在其内部提供了一个buffer,在读数据时,会一次读取一大块数据到buffer中,这样比单字节的操作效率要高的多,特别是进程磁盘IO和对大量数据进行读写的时候,能提升IO性能。

*   **PushbackInputStream**

    > PushbackInputStream 内部同样使用一个 buf 字节数组对已读数据进行缓存,然后可以通过 unread 方法将已读的数据重新放回 buf 数组,从而实现了一个支持 push back 的字节流类。

*   **DataInputStream**

    > DataInputStream 提供了许多可以读取 Java 基本类型的方法。

#### ByteArrayInputStream

ByteArrayInputStream 支持从 byte 数组读取数据,通过构造函数可以指定该 byte 数组:

protected byte buf[];

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;
}

#### ObjectInputStream

ObjectInputStream 与 DataInputStream 类似也支持 Java 基本类型的读取,此外还支持反序列化读取对象。它常常与 ObjectOutputStream 搭配使用。因此,ObjectOutputStream 实现将基本类型或者对象序列化并输出到 IO 字节流或者设备上,而 ObjectInputStream 从 IO 字节流或者设备上反序列化读取基本类型或者对象。

比如,从文件中读取一个 person 对象。

ObjectInputStream input = new ObjectInputStream(new FileInputStream("data.txt"));
Person person = (MyClass) input.readObject();
input.close();


这里要求 Person 一定要实现 java.io.Serializable 接口。

#### PipedInputStream

PipedInputStream 通常和 PipedOutputStream 搭配使用,实现了一个承载字节流的管道类。PipedOutputStream 的输出会自动调用 PipedInputStream 的 receive 方法作为输入。PipedInputStream 提供了以下几个特殊方法:

// 连接 PipedOutputStream 对象,形成管道
public void connect(PipedOutputStream src) throws IOException;
// 接收一个字节
protected synchronized void receive(int b) throws IOException;
// 接收一个字节数组
synchronized void receive(byte b[], int off, int len) throws IOException;


注意到其 read 方法和 receive 都是同步方法,read 方法在没有数据的时候会发生阻塞,而 receive 方法在缓冲数组没有剩余空间的时候也会发生阻塞:

public synchronized int read() throws IOException {
if (!connected) {
throw new IOException("Pipe not connected");
} else if (closedByReader) {
throw new IOException("Pipe closed");
} else if (writeSide != null && !writeSide.isAlive()
&& !closedByWriter && (in < 0)) {
throw new IOException("Write end dead");
}

    readSide = Thread.currentThread();
    int trials = 2;
    while (in < 0) {
        // in小于0表示缓冲数组为空,处于无数据状态
        if (closedByWriter) {
            /* closed by writer, return EOF */
            return -1;
        }
        if ((writeSide != null) && (!writeSide.isAlive()) && (--trials < 0)) {
            throw new IOException("Pipe broken");
        }
        /* might be a writer waiting */
        notifyAll();
        try {
            // 阻塞等待
            wait(1000);
        } catch (InterruptedException ex) {
            throw new java.io.InterruptedIOException();
        }
    }
    int ret = buffer[out++] & 0xFF;
    if (out >= buffer.length) {
        out = 0;
    }
    if (in == out) {
        /* now empty */
        in = -1;
    }

    return ret;
}

protected synchronized void receive(int b) throws IOException {
checkStateForReceive();
writeSide = Thread.currentThread();
if (in == out)
// 当in等于out,意味着缓冲数组已满,阻塞等待空间释放
awaitSpace();
if (in < 0) {
in = 0;
out = 0;
}
buffer[in++] = (byte)(b & 0xFF);
if (in >= buffer.length) {
in = 0;
}
}


#### SequenceInputStream

SequenceInputStream 支持将多个 InputStream 组合起来,并按照顺序进行读取。

### OutputStream

OutputStream 与 InputStream 相对应,实现上存在很多相似之处。先看看内部方法:

public abstract class OutputStream implements Closeable, Flushable {
public abstract void write(int b) throws IOException;
public void write(byte b[]) throws IOException {//}
public void write(byte b[], int off, int len) throws IOException {/
/}
public void flush() throws IOException {//}
public void close() throws IOException {/
/}
}


OutputStream 实现了 Closeable 接口和 Flushable 方法,同样有一个抽象的 write 方法需要实现。其他方法提供框架性代码,也需要实现类覆写相关方法,提供更多的自定义功能。

#### FileOutputStream

实现上与 FileInputStream 类似,提供对文件写入字节流的功能。

#### FilterOutputStream

与 FilterInputStream 类似,对 OutputStream 对象进行包装,并继承了 OutputStream 并覆写全部方法,方法内容都是简单地调用内部的 OutputStream 对象。

同样的也有几个子类实现:

*   **BufferedOutputStream**:带缓冲区的字节流输出类,与 BufferedInputStream 对应;
*   **DataOutputStream**:提供写 Java 基本类型相关方法的字节流类,与 DataInputStream 对应;
*   **PrintStream**:与 DataOutputStream 有些类似,不过它提供了更加丰富的写出方法,并且支持换行输出。

#### ByteArrayOutputStream

与 ByteArrayInputStream 相反,ByteArrayOutputStream 实现输出到内部的缓存字节数组 buf 中。特有的方法有:

/** 将该 Stream 输出为 byte 数组/
public synchronized byte toByteArray()[] {
return Arrays.copyOf(buf, count);
}
/
将该 Stream 输出到另一个 Stream 上**/
public synchronized void writeTo(OutputStream out) throws IOException {
out.write(buf, 0, count);
}


#### ObjectOutputStream

与 ObjectInputStream 对应,ObjectOutputStream 实现将 Java 基本类型数据或者 Java 对象序列化后写入输出字节流中。

#### PipedOutputStream

与 PipedInputStream 搭配使用,PipedOutputStream 会输出字节流到管道另一端的 PipedInputStream。

## 字符流

字节流处理的是 byte 数组,而字符流处理的是 char 数组。而且字符流相关的类都以 Reader 或者 Writer 为后缀。

### Reader

先看看内部方法:

public abstract class Reader implements Readable, Closeable {
public int read(java.nio.CharBuffer target) throws IOException;
public int read() throws IOException;
public int read(char cbuf[]) throws IOException;
abstract public int read(char cbuf[], int off, int len) throws IOException;
public long skip(long n) throws IOException;
public boolean ready() throws IOException;
public boolean markSupported();
public void mark(int readAheadLimit) throws IOException;
public void reset() throws IOException;
abstract public void close() throws IOException;
}


内部方法与 InputStream 非常相似,同样实现类需要实现 read 方法。

#### BufferedReader

带缓冲区的 Reader 实现。

#### CharArrayReader

从字符数组读取数据的 Reader 实现。

#### InputStreamReader

InputStreamReader 是一个包装类,内部对象是 StreamDecoder。StreamDecoder 支持从 InputStream 中读取字符。

public class InputStreamReader extends Reader {

private final StreamDecoder sd;

/**
 * Creates an InputStreamReader that uses the default charset.
 *
 * @param  in   An InputStream
 */
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);
    }
}

最后

做任何事情都要用心,要非常关注细节。看起来不起眼的、繁琐的工作做透了会有意想不到的价值。
当然要想成为一个技术大牛也需要一定的思想格局,思想决定未来你要往哪个方向去走, 建议多看一些人生规划方面的书籍,多学习名人的思想格局,未来你的路会走的更远。

更多的技术点思维导图我已经做了一个整理,涵盖了当下互联网最流行99%的技术点,在这里我将这份导图分享出来,以及为金九银十准备的一整套面试体系,上到集合,下到分布式微服务

Java面试官:开发过程中

Java面试官:开发过程中

Java面试官:开发过程中

Java面试官:开发过程中

如何获得这套优质的资料呢?

Java面试精选题、架构实战文档传送门:戳这里免费领取

上一篇:自学Java第二十六课


下一篇:javaSE 笔记 异常 + try...catch... + throws/throw + 自定义异常