MST

星途 面试题库

面试题:Java中如何在Java I/O中基于装饰者模式实现自定义缓冲流

假设你要基于Java I/O的装饰者模式,实现一个自定义的缓冲流来提高文件读取效率。请描述实现思路,并给出关键代码片段,包括如何继承和组合相关的I/O类,以及如何重写关键方法。
16.2万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 继承抽象装饰者类:Java I/O中的FilterInputStream(用于字节流)或FilterReader(用于字符流)是抽象装饰者类,自定义缓冲流需继承其中之一。
  2. 组合基础流:在自定义类的构造函数中,接受一个基础的输入流对象,以便在装饰者模式中对其进行功能增强。
  3. 实现缓冲机制:定义一个缓冲区数组,重写read方法来实现从缓冲区读取数据,当缓冲区数据读完后,再从基础流中填充缓冲区。

关键代码片段(以字节流为例,继承FilterInputStream

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;

public class MyBufferedInputStream extends FilterInputStream {
    private static final int DEFAULT_BUFFER_SIZE = 8192;
    private byte[] buffer;
    private int count;
    private int pos;

    public MyBufferedInputStream(InputStream in) {
        this(in, DEFAULT_BUFFER_SIZE);
    }

    public MyBufferedInputStream(InputStream in, int size) {
        super(in);
        if (size <= 0) {
            throw new IllegalArgumentException("Buffer size <= 0");
        }
        buffer = new byte[size];
    }

    @Override
    public int read() throws IOException {
        if (pos >= count) {
            fillBuffer();
            if (pos >= count) {
                return -1;
            }
        }
        return buffer[pos++] & 0xff;
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        if (len == 0) {
            return 0;
        }
        int avail = count - pos;
        if (avail <= 0) {
            if ((count = fillBuffer()) <= 0) {
                return -1;
            }
            avail = count - pos;
        }
        int cnt = (avail < len)? avail : len;
        System.arraycopy(buffer, pos, b, off, cnt);
        pos += cnt;
        return cnt;
    }

    private int fillBuffer() throws IOException {
        pos = 0;
        return in.read(buffer);
    }
}

关键方法重写说明

  1. read()方法:首先检查缓冲区是否还有数据,如果没有则调用fillBuffer()方法填充缓冲区,然后从缓冲区返回一个字节数据。
  2. read(byte[] b, int off, int len)方法:计算缓冲区中可用的数据量,如果不够则填充缓冲区,然后将缓冲区中的数据复制到目标数组b中,返回实际读取的字节数。
  3. fillBuffer()方法:从基础输入流in中读取数据填充到缓冲区,并返回读取的字节数。如果读取到流末尾则返回 -1。