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方法