java io流以inputstream、outputstream、reader、writer四个抽象类为根基,而非接口,因其可提供默认实现(如skip)、预留模板方法、支持字段状态;体系分节点流、处理流、转换流三层,依托装饰器模式组合功能。

Java IO流库中并没有“接口”作为顶层抽象,而是以四个抽象类为根基构建整个体系——InputStream、OutputStream、Reader、Writer。它们不是接口,但承担了类似接口的契约角色:定义统一方法签名,强制子类实现核心行为(如 read()、write()),同时保留可选功能(如 mark()/reset())的灵活性。
为什么用抽象类而非接口?
早期Java(JDK 1.0)设计IO时,抽象类能兼顾两方面需求:
- 提供部分默认实现(如
InputStream.skip()基于read()的朴素实现,供子类按需重写) - 预留模板方法扩展点(如
FilterInputStream在read()前后插入逻辑) - 避免接口无法携带状态或字段的限制(缓冲流需维护内部
byte[] buf)
抽象类如何支撑层级扩展?
四大基类各自形成独立继承树,每层聚焦不同职责:
-
节点流层(如
FileInputStream、FileReader):直接关联物理资源,负责原始数据读写 -
处理流层(如
BufferedInputStream、PrintWriter):包装上游流,增强功能(缓冲、格式化、编码转换) -
转换流层(
InputStreamReader/OutputStreamWriter):桥接字节与字符世界,显式指定字符集
装饰器模式是层级协作的核心机制
所有处理流都遵循装饰器原则:构造时接收一个已存在的流对象,自身方法调用最终委托给被装饰流。例如:
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
调用 bis.read() 时,先尝试从内部缓冲区取数据;缓冲区空则触发 FileInputStream.read(),再填充缓冲区。这种组合方式让功能叠加清晰可控,无需为每种组合预定义类。
实际开发中的关键认知
理解层级本质比死记类名更重要:
- 选字节流还是字符流?看数据本质:二进制文件(图片/音频)用
InputStream系,纯文本优先用Reader系(自动解码) - 是否需要缓冲?几乎总是需要——未缓冲的
FileInputStream单字节读取性能极差,应搭配BufferedInputStream或直接用Files.newInputStream()(NIO.2 自带缓冲) - 跨编码读文本?必须用
InputStreamReader显式指定 charset,否则依赖平台默认编码(Windows常为GBK,Linux/macOS为UTF-8),极易乱码
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











