CharBuffer源码

CharBuffer阅读笔记

一、简介

它是一个抽象类,具体实现都是在子类,但是可以通过自身的静态方法实例化不同的构造,Buffer的第一级子类

采用了《模板模式》的设计模式

二、继承关系图

  • 相关实现
    在这里插入图片描述
  • CharSequence 就是一个字符串的描述接口,有2个主要的抽象方法-charAt(int)和subSequence(int,int),还有toString,length,chars,codePonts方法,
  • Appendable:就是一个字符缓存块追加字符的描述接口
  • Readable:就是一个字符缓存块读取的描述接口

三、存储结构

  • 自身有char数组的存储结构,
  • 如果是堆外直接物理内存Direct*、String*、ByteBufferAsCharBuffer*等是用的自己的数据接口。

四、源码分析

内部类

属性
/** 这是真正的数据存储数组,下面的3个数据都只支持JVM堆内缓存块*/
final char[] hb;                  // Non-null only for heap buffers
final int offset;
/** 通过asReadOnlyBuffer实例化的都是readOnly仅读 */
boolean isReadOnly;                 // Valid only for heap buffers
构造
// Creates a new buffer with the given mark, position, limit, capacity,
// backing array, and array offset
/**
 * 直接初始化数组,并可以自定义四大属性和数组及数组偏移值
 */
IntBuffer(int mark, int pos, int lim, int cap,   // package-private
          int[] hb, int offset){
    // 初始化4大属性,数组,数组偏移值
    super(mark, pos, lim, cap);
    this.hb = hb;
    this.offset = offset;
} 

// Creates a new buffer with the given mark, position, limit, and capacity
//
/**
 * 不会用设置自身的数组,会设置其他的操作存储对象(如直接内存,或其他CharSequence对象)
 * 仅用于ByteBufferAsCharBuffer* 或DirectCharBuffer* 或StringCharBuffer
 * ByteBufferAsCharBuffer 内含一个ByteBuffer对象,传入的char但是操作的其实是ByteBuffer
 */
IntBuffer(int mark, int pos, int lim, int cap) { // package-private
    this(mark, pos, lim, cap, null, 0);
}
主要方法
1、创建缓存区(静态方法)
  • 1

    /** 生成一个固定容量的char缓存区 */
    public static CharBuffer allocate(int capacity) {
        // 参数 效验
        if (capacity < 0)
            throw new IllegalArgumentException();
        // 直接生成堆内char缓存区
        return new HeapCharBuffer(capacity, capacity);
    }
    /** 
     * 根据传入的数组,生成一个缓存块
     * array 传入操作数组
     * offset 传入操作其实位置,也就是初始化position
     * length 可操作数量,也就是offset+length=limit
     */
    public static CharBuffer wrap(char[] array,
                                  int offset, int length)
    {
        try {
            return new HeapCharBuffer(array, offset, length);
        } catch (IllegalArgumentException x) {
            throw new IndexOutOfBoundsException();
        }
    }
    
    /** 根据传入的数组生成一个缓存块 ,position默认为0,limit默认为数组大小*/
    public static CharBuffer wrap(char[] array) {
        return wrap(array, 0, array.length);
    }
    
    /**
     * 根据传入的csq生成一个StringCharBuffer缓存块,
     * csq就是内部真正的缓存块对象
     */
    public static CharBuffer wrap(CharSequence csq) {
        return wrap(csq, 0, csq.length());
    }
    
    /**
     * csq 字符串描述接口类型(String,StringBuffer,StringBuilder等)
     * start 用于生成 position
     * end 用于生成limit  等于 start+end=limit
     * StringCharBuffer缓存块是操作的自己的CharSequence对象
     */
    public static CharBuffer wrap(CharSequence csq, int start, int end) {
        try {
            return new StringCharBuffer(csq, start, end);
        } catch (IllegalArgumentException x) {
            throw new IndexOutOfBoundsException();
        }
    }
    
2、get/read相关方法
  • 需要传入读取缓存快的数据后,用于接受数据的数组或缓冲块

    /**
     * read方法是对Readable接口的实现
     * 使用target缓冲块读取自身的数据
     */
    public int read(CharBuffer target) throws IOException {
        // Determine the number of bytes n that can be transferred
        // 获取target的剩余容量
        int targetRemaining = target.remaining();
        // 获取自身可读取的剩余容量大小
        int remaining = remaining();
        if (remaining == 0)
            return -1;
        // 此次读取的容量大小
        int n = Math.min(remaining, targetRemaining);
        // 临时缓存limit,用于读取后的恢复使用
        int limit = limit();
        // Set source limit to prevent target overflow
        if (targetRemaining < remaining)
            // 如果目标剩余容量小于自身可读写的容量,则进行limit设置最佳
            // 说明n是targetRemaininig的值,所以设置limit为最佳
            limit(position() + n);
        try {
            if (n > 0)
                // 对this的可读写范围作了设置,然后直接把可操作的容量区域下入到target
                target.put(this);
        } finally {
            // 恢复自身的limit
            limit(limit); // restore real limit
        }
        return n;
    }
    
    /** 
     * 读取this的数据到dst数组中,
     * offeset 写入的数组起始位置
     * length 此次读取的数据长度
     */
    public CharBuffer get(char[] dst, int offset, int length) {
        // 数组的边界效验
        checkBounds(offset, length, dst.length);
        // this中数据不能小于此次读写的大小
        if (length > remaining())
            throw new BufferUnderflowException();
        int end = offset + length;
        for (int i = offset; i < end; i++)
            // 读取this数据写入的奥dst
            dst[i] = get();
        return this;
    }
    
    /**
     * 读取this的输入写入到dst数组中,
     * 根据上一个函数的规则,那么传入的char数组的长度 不能大于this缓存块可读写的容量大小
     */
    public CharBuffer get(char[] dst) {
        return get(dst, 0, dst.length);
    }
    
3、put相关方法
  • 需要传入待写入的数组或缓存块

    /**
     * src 缓冲块
     * 读取src的数据,写入到自身
     */
    public CharBuffer put(CharBuffer src) {
        // 参数效验
        // 1. 不能是自身
        // 2. 判断是否是只读缓存块(通过asReadOnlyBuffer生成的缓存块)
        // 3. src可读写的容量大小不能超过this自身的可读写容量大小
        if (src == this)
            throw new IllegalArgumentException();
        if (isReadOnly())
            throw new ReadOnlyBufferException();
        int n = src.remaining();
        if (n > remaining())
            throw new BufferOverflowException();
        // 开始读取src的数据,写入到自身
        for (int i = 0; i < n; i++)
            put(src.get());
        return this;
    }
    
    /**
     * 读取数组的数据,写入到自身的缓冲块
     * src 待读取的数据数组
     * offset 待读取的数组的起始读取位置
     * length 待写入的数据量大小
     */
    public CharBuffer put(char[] src, int offset, int length) {
        // 数组相关参数边界效验
        checkBounds(offset, length, src.length);
        // 写入的容量不可大于自身可读写的容量
        if (length > remaining())
            throw new BufferOverflowException();
        int end = offset + length;
        for (int i = offset; i < end; i++)
            // 写入数据
            this.put(src[i]);
        return this;
    }
    
    /**
     * 把数组中的数据写入到缓存块
     * 根据上面函数知道,会做一些效验,也就是数组的大小不可超过自身剩余可读写的容量
     */
    public final CharBuffer put(char[] src) {
        return put(src, 0, src.length);
    }
    
    /**
     * 把字符串的数据写入到缓存块
     * start 字符串读取的起始索引
     * end   字符串读取的结束索引
     */
    public CharBuffer put(String src, int start, int end) {
        // 效验
        // 1.边界效验
        // 2.判断是否是只读缓存块(通过asReadOnlyBuffer生成的缓存块)
        // 3.本次写入的长度不可大于自身剩余可写入的容量大小
        checkBounds(start, end - start, src.length());
        if (isReadOnly())
            throw new ReadOnlyBufferException();
        if (end - start > remaining())
            throw new BufferOverflowException();
        for (int i = start; i < end; i++)
            // 写入数据
            this.put(src.charAt(i));
        return this;
    }
    /**
     * 把字符串的数据全部写入到缓存块 
     * 根据上面的函数知道,会做一些效验,也就是字符串的长度不可超过自身剩余可读写的容量
     */
    public final CharBuffer put(String src) {
        return put(src, 0, src.length());
    }
    
4、append相关方法
  • 是Appendable接口的实现方法

    /**
     * 把char字符的数据写入到自身缓冲块
     */
    public CharBuffer append(char c) {
        // 多态调用子类的方法
        return put(c);
    }
    
    /** 
     * 把CharSequence的数据写入到自身的缓存快
     * CharSequence接口有一些实现例如:String、StringBuffer、StringBuilder等
     * 如果追加对象是null 则直接写入“null”字符串
     */
    public CharBuffer append(CharSequence csq) {
        if (csq == null)
            return put("null");
        else
            return put(csq.toString());
    }
    
    /**
     * 把CharSequence的数组写入到自身的缓存快,并且限定从start起始写入,end为结束索引(不含end)
     */
    public CharBuffer append(CharSequence csq, int start, int end) {
        // 处理CharSequence为null的情况
        CharSequence cs = (csq == null ? "null" : csq);
        // subSequence函数就是做字符串的处理,会有边界效验
        // 调用上面的CharBuffer put(String src)方法
        return put(cs.subSequence(start, end).toString());
    }
    
5、其他方法
  • 其他方法都是基本都是常用方法或者抽象方法
补充

五、总结

注意:length()方法,等价remaining方法

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值