对比FastByteArrayOutputStream与ByteArrayOutputStream的区别
ByteArrayOutputStream
1、基本数据结构:protected byte buf[]; 一维结构
2、write方法:写数组,改变count
1 2 3 4 5 6 7 8 9 10 11 | public synchronized void write( byte b[], int off, int len) { if ((off < 0 ) || (off > b.length) || (len < 0 ) || ((off + len) - b.length > 0 )) { throw new IndexOutOfBoundsException(); } // 判断是否需要扩容 ensureCapacity(count + len); // 写数据 System.arraycopy(b, off, buf, count, len); count += len; } |
3、静态扩容(每一次创建一个新数组 byte[]):
1 2 3 4 5 6 7 8 9 10 11 | private void grow( int minCapacity) { // overflow-conscious code int oldCapacity = buf.length; int newCapacity = oldCapacity << 1 ; if (newCapacity - minCapacity < 0 ) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0 ) newCapacity = hugeCapacity(minCapacity); // 创建一个新数组。 buf = Arrays.copyOf(buf, newCapacity); } |
FastByteArrayOutputStream
1、基本数据结构:private final Deque<byte[]> buffers;
一个存放 byte[] 的deque,二维结构
2、write方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | public void write( byte [] data, int offset, int length) throws IOException { if (offset >= 0 && offset + length <= data.length && length >= 0 ) { if ( this .closed) { throw new IOException( "Stream closed" ); } else { if ( this .buffers.peekLast() == null || (( byte []) this .buffers.getLast()).length == this .index) { // 如果 deque中最后一个byte[]不存在,或者已经满了,则 新增一个byte[],放到deque尾部 this .addBuffer(length); } if ( this .index + length > (( byte []) this .buffers.getLast()).length) { int pos = offset; // 循环创建、循环写数据 do { if ( this .index == (( byte []) this .buffers.getLast()).length) { // 如果已经满了,就新增一个,放到deque尾部 this .addBuffer(length); } int copyLength = (( byte []) this .buffers.getLast()).length - this .index; if (length < copyLength) { copyLength = length; } // 写数据,到deque尾部的byte[]中 System.arraycopy(data, pos, this .buffers.getLast(), this .index, copyLength); pos += copyLength; this .index += copyLength; length -= copyLength; } while (length > 0 ); } else { System.arraycopy(data, offset, this .buffers.getLast(), this .index, length); this .index += length; } } } else { throw new IndexOutOfBoundsException(); } } |
1. 找到deque中最后一个 byte数组,写数据到这个数组中
2. 如果这个 数组写不下了,就再创建一个 byte[]数组,放到deque尾部,继续写 (动态扩容,每次只新增一小部分)。
结论:
1、FastByteArrayOutputStream的基础数据结构,相比于ByteArrayOutPutStream的一维数组,它用了一个 二维的数据结构来存放数据。
2、当数据满了需要扩容时,ByteArrayOutPutStream只能重新创建一个容量更大的byte[],来替换之前的,并且复制数据到新byte[]中
3、而FastByteArrayOutputStream,只需要在deque中,再创建一个byte[],直接写数据,写满了,再建一个,放在deque最后。
之前的数据不需要改动,不需要大量的复制操作。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下