java源码-BufferedReader

简介: 开篇 在设计模式中有一种叫做装饰者模式,刚好BufferedReader的源码是这个设计模式的最好例子,一并看下源码。源码分析构造函数BufferedReader的类变量的Reader in 用以构造函数参数中的Reader in参数,BufferedReader的所有读写操作都通过Reader对象进行操作。

开篇

 在设计模式中有一种叫做装饰者模式,刚好BufferedReader的源码是这个设计模式的最好例子,一并看下源码。


源码分析

构造函数

  • BufferedReader的类变量的Reader in 用以构造函数参数中的Reader in参数,BufferedReader的所有读写操作都通过Reader对象进行操作。
  • BufferedReader相当于针对内部的Reader对象进行了一层包装,可以理解为装饰者。
public class BufferedReader extends Reader {
    private Reader in;
    private char cb[];
    //nextChar代表下次要读取的位置,nChars表示总共的字符个数
    private int nChars, nextChar;

    private static final int INVALIDATED = -2;
    private static final int UNMARKED = -1;
    private int markedChar = UNMARKED;
    private int readAheadLimit = 0; /* Valid only when markedChar > 0 */
    private boolean skipLF = false;
    private boolean markedSkipLF = false;
    private static int defaultCharBufferSize = 8192;
    private static int defaultExpectedLineLength = 80;

    public BufferedReader(Reader in, int sz) {
        super(in);
        if (sz <= 0)
            throw new IllegalArgumentException("Buffer size <= 0");
        this.in = in;
        cb = new char[sz];
        nextChar = nChars = 0;
    }

    public BufferedReader(Reader in) {
        this(in, defaultCharBufferSize);
    }
}



加载数据

  • 负责通过Reader in对象读取字符到指定数量的字符数据到cb数组当中。
  • dst表示保存数据的起始位置,cb.length-dst表示读取字符的个数。
  • 在执行read和readline操作的之前如果cb当中可读字符不足会先执行fill()读取字符。
 private void fill() throws IOException {
        int dst;
        if (markedChar <= UNMARKED) {
            /* No mark */
            dst = 0;
        } else {
            // 省略一部分代码
        }

        int n;
        do {
            // 从底层input读取数据到cb,cb中起始位置是dst, 
            // 读取的长度是cb的lenght减去起始位置dst,理解剩余能够装的字符
            n = in.read(cb, dst, cb.length - dst);
        } while (n == 0);
        if (n > 0) {
            // 设置最大可读字符结束位置
            nChars = dst + n;
            // 设置可读字符的起始位置
            nextChar = dst;
        }
    }



read过程

  • 读取过程中如果满足条件(nextChar 表示下一个读取字符>= nChars可用字符),代表字符已经读取完毕那么就通过fill()进行预加载。
  • 读取当前字符并累加当前可读取字符,执行nextChar++操作。
    public int read() throws IOException {
        synchronized (lock) {
            ensureOpen();
            for (;;) {
                if (nextChar >= nChars) {
                    fill();
                    if (nextChar >= nChars)
                        return -1;
                }
                if (skipLF) {
                    skipLF = false;
                    if (cb[nextChar] == '\n') {
                        nextChar++;
                        continue;
                    }
                }
                // 读取当前字符并累加下一个读取位置
                return cb[nextChar++];
            }
        }
    }



readline过程

  • 读取过程中如果满足条件(nextChar 表示下一个读取字符>= nChars可用字符),代表字符已经读取完毕那么就通过fill()进行预加载。
  • 读取过程中如果遇到\r\n则中断循环,通过str = new String(cb, startChar, i - startChar)返回整行数据。
    String readLine(boolean ignoreLF) throws IOException {
        //读取的数据最终放在这个s中,
        StringBuffer s = null;
        int startChar;

        synchronized (lock) {
            ensureOpen();
            boolean omitLF = ignoreLF || skipLF;

        bufferLoop:
            for (;;) {

                if (nextChar >= nChars)
                    fill();
                if (nextChar >= nChars) { /* EOF */
                    if (s != null && s.length() > 0)
                        //从这里返回,可能是因为读取的数据最后没有以\n或\r结束
                        return s.toString();
                    else
                        // 从这里返回,是因为开始读的时候,就已经是input的末尾了,
                        // 所以s本身就没有被初始化,只能返回null
                        return null;
                }
                boolean eol = false;
                char c = 0;
                int i;

                /* Skip a leftover '\n', if necessary */
                if (omitLF && (cb[nextChar] == '\n'))
                    nextChar++;
                skipLF = false;
                omitLF = false;

            charLoop:
                for (i = nextChar; i < nChars; i++) {
                    c = cb[i];
                    if ((c == '\n') || (c == '\r')) {
                        eol = true;
                        break charLoop;
                    }
                }

                startChar = nextChar;
                nextChar = i;

                if (eol) {
                    String str;
                    // 运行到这,s为null,说明是第一次循环中就读到了行尾。
                    if (s == null) {
                        str = new String(cb, startChar, i - startChar);
                    } else {
                        // 运行到这,起码说明是第二次循环了,s里已经有了第一次读取的数据
                        s.append(cb, startChar, i - startChar);
                        str = s.toString();
                    }
                    nextChar++;
                    if (c == '\r') {
                        skipLF = true;
                    }
                    // 运行到这说明读到了行尾,返回str
                    return str;
                }

                if (s == null)
                    s = new StringBuffer(defaultExpectedLineLength);
                // 运行到这说明,读取了整个cb的数据,发现一直没有\n或者\r, 
                // 之后回到最初循环继续读取。
                s.append(cb, startChar, i - startChar);
            }
        }
    }


类依赖图

  • BufferedReader的类依赖图如下图,所有的io reader都是继承自Reader作为基类。


    img_62acfe3000fc52dee4f6ff8ac42c2045.png


装饰设计模式

装饰设计模式:javaIO技术中的装饰设计模式,对一组对象的功能进行增强时,就可以使用该设计模式

目录
相关文章
|
11月前
|
前端开发 Java 关系型数据库
基于Java+Springboot+Vue开发的鲜花商城管理系统源码+运行
基于Java+Springboot+Vue开发的鲜花商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的鲜花商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。技术学习共同进步
671 7
|
11月前
|
消息中间件 算法 安全
JUC并发—1.Java集合包底层源码剖析
本文主要对JDK中的集合包源码进行了剖析。
|
11月前
|
人工智能 安全 Java
智慧工地源码,Java语言开发,微服务架构,支持分布式和集群部署,多端覆盖
智慧工地是“互联网+建筑工地”的创新模式,基于物联网、移动互联网、BIM、大数据、人工智能等技术,实现对施工现场人员、设备、材料、安全等环节的智能化管理。其解决方案涵盖数据大屏、移动APP和PC管理端,采用高性能Java微服务架构,支持分布式与集群部署,结合Redis、消息队列等技术确保系统稳定高效。通过大数据驱动决策、物联网实时监测预警及AI智能视频监控,消除数据孤岛,提升项目可控性与安全性。智慧工地提供专家级远程管理服务,助力施工质量和安全管理升级,同时依托可扩展平台、多端应用和丰富设备接口,满足多样化需求,推动建筑行业数字化转型。
384 5
|
11月前
|
存储 Java
【源码】【Java并发】【ThreadLocal】适合中学者体质的ThreadLocal源码阅读
前言 下面,跟上主播的节奏,马上开始ThreadLocal源码的阅读( ̄▽ ̄)" 内部结构 如下图所示,我们可以知道,每个线程,都有自己的threadLocals字段,指向ThreadLocalMap
599 81
【源码】【Java并发】【ThreadLocal】适合中学者体质的ThreadLocal源码阅读
|
6月前
|
存储 小程序 Java
热门小程序源码合集:微信抖音小程序源码支持PHP/Java/uni-app完整项目实践指南
小程序已成为企业获客与开发者创业的重要载体。本文详解PHP、Java、uni-app三大技术栈在电商、工具、服务类小程序中的源码应用,提供从开发到部署的全流程指南,并分享选型避坑与商业化落地策略,助力开发者高效构建稳定可扩展项目。
|
11月前
|
前端开发 Java 物联网
智慧班牌源码,采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署
智慧班牌系统是一款基于信息化与物联网技术的校园管理工具,集成电子屏显示、人脸识别及数据交互功能,实现班级信息展示、智能考勤与家校互通。系统采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署与私有化定制。核心功能涵盖信息发布、考勤管理、教务处理及数据分析,助力校园文化建设与教学优化。其综合性和可扩展性有效打破数据孤岛,提升交互体验并降低管理成本,适用于日常教学、考试管理和应急场景,为智慧校园建设提供全面解决方案。
631 70
|
10月前
|
JavaScript Java 关系型数据库
家政系统源码,java版本
这是一款基于SpringBoot后端框架、MySQL数据库及Uniapp移动端开发的家政预约上门服务系统。
316 6
家政系统源码,java版本
|
10月前
|
供应链 JavaScript 前端开发
Java基于SaaS模式多租户ERP系统源码
ERP,全称 Enterprise Resource Planning 即企业资源计划。是一种集成化的管理软件系统,它通过信息技术手段,将企业的各个业务流程和资源管理进行整合,以提高企业的运营效率和管理水平,它是一种先进的企业管理理念和信息化管理系统。 适用于小微企业的 SaaS模式多租户ERP管理系统, 采用最新的技术栈开发, 让企业简单上云。专注于小微企业的应用需求,如企业基本的进销存、询价,报价, 采购、销售、MRP生产制造、品质管理、仓库库存管理、财务应收付款, OA办公单据、CRM等。
639 23
|
11月前
|
Java
【源码】【Java并发】【ReentrantLock】适合中学者体质的ReentrantLock源码阅读
因为本文说的是ReentrantLock源码,因此会默认,大家对AQS有基本的了解(比如同步队列、条件队列大概> 长啥样?)。 不懂AQS的小朋友们,你们好呀!也欢迎先看看这篇
242 13
【源码】【Java并发】【ReentrantLock】适合中学者体质的ReentrantLock源码阅读
|
11月前
|
Java
【源码】【Java并发】【AQS】从ReentrantLock、Semaphore、CutDownLunch、CyclicBarrier看AQS源码
前言 主播觉得,AQS的原理,就是通过这2个队列的协助,实现核心功能,同步队列(CLH队列)和条件队列(Condition队列)。 同步队列(CLH队列) 作用:管理需要获...
214 18
【源码】【Java并发】【AQS】从ReentrantLock、Semaphore、CutDownLunch、CyclicBarrier看AQS源码