缓冲区 Buffer
private int mark = - 1 ;
private int position = 0 ;
private int limit;
private int capacity;
实现子类
子类 描述 ByteBuffer
存储字节(byte),最常用的 Buffer 类型,内定义了数组 CharBuffer
存储字符(char) ShortBuffer
存储短整型(short) IntBuffer
存储整型(int) LongBuffer
存储长整型(long) FloatBuffer
存储浮点型(float) DoubleBuffer
存储双精度浮点型(double)
真正实现类
Buffer 抽象子类 常见实现类 描述 ByteBuffer
HeapByteBuffer
、DirectByteBuffer
最常用的 Buffer 类型,有堆内和直接内存实现,数组存在堆中,使用父类数组,实现父类定义的操作 CharBuffer
HeapCharBuffer
、DirectCharBufferU
等存储 char 类型数据 ShortBuffer
HeapShortBuffer
、DirectShortBufferU
等存储 short 类型数据 IntBuffer
HeapIntBuffer
、DirectIntBufferU
等存储 int 类型数据 LongBuffer
HeapLongBuffer
、DirectLongBufferU
等存储 long 类型数据 FloatBuffer
HeapFloatBuffer
、DirectFloatBufferU
等存储 float 类型数据 DoubleBuffer
HeapDoubleBuffer
、DirectDoubleBufferU
等存储 double 类型数据
如何创建缓冲区
public static void main ( String [ ] args) throws IOException {
IntBuffer buffer = IntBuffer . allocate ( 10 ) ;
int [ ] array = { 1 , 2 , 3 , 4 , 5 } ;
IntBuffer buffer1 = IntBuffer . wrap ( array) ;
IntBuffer buffer2 = IntBuffer . wrap ( array, 1 , 3 ) ;
}
缓冲区写操作
public static void main ( String [ ] args) {
IntBuffer buffer = IntBuffer . allocate ( 10 ) ;
buffer. put ( 1 ) ;
buffer. put ( 1 , 999 ) ;
int [ ] arr = new int [ ] { 666 , 555 } ;
buffer. put ( arr) ;
buffer. put ( 0 , arr) ;
buffer. put ( arr, 1 , 1 ) ;
buffer. put ( 0 , arr, 1 , 1 ) ;
IntBuffer buffer1 = IntBuffer . wrap ( new int [ ] { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 } ) ;
buffer. put ( 4 , buffer1, 0 , 6 ) ;
buffer. put ( buffer1) ;
System . out. println ( Arrays . toString ( buffer. array ( ) ) ) ;
}
缓冲区读操作
注意,执行完写操作后想要进行读之前,要执行filp()方法翻转:limit = position; position = 0;
方法 是否预设数据 初始 position 初始 limit 读前是否要 flip wrap(arr)
✅ 是 0 arr.length ❌ 不需要 allocate(capacity)
❌ 否 0 capacity ✅ 需要
public static void main ( String [ ] args) {
int [ ] arr = new int [ ] { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 } ;
IntBuffer buffer = IntBuffer . wrap ( arr) ;
buffer. get ( ) ;
buffer. get ( ) ;
buffer. get ( 1 ) ;
int [ ] arr2 = new int [ 8 ] ;
buffer. get ( 0 , arr2, 3 , 3 ) ;
System . out. println ( buffer) ;
System . out. println ( Arrays . toString ( arr2) ) ;
System . out. println ( Arrays . toString ( buffer. array ( ) ) ) ;
}
public static void main ( String [ ] args) {
int [ ] arr = new int [ ] { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 } ;
IntBuffer buffer = IntBuffer . wrap ( arr) ;
buffer. get ( ) ;
buffer. mark ( ) ;
System . out. println ( buffer. get ( ) ) ;
buffer. reset ( ) ;
System . out. println ( buffer. get ( ) ) ;
}
其他缓冲区操作
方法 作用 常见用途 是否影响数据 flip()
写转读 写完准备读取 ❌ 不改内容 clear()
清空缓冲区,准备写 读完准备写新数据 ❌(内容还在,只是重置) rewind()
重绕到头 想重复读取数据 ❌ compact()
压缩未读数据到前面,准备继续写 边读边写、半包处理等 ✅ 改位置 mark()
+ reset()
标记/回到某个位置 回退、回看 ❌ hasRemaining()
/ remaining()
判断/获取剩余数据 循环中判断读完没 ❌ duplicate()
拷贝一个共享数据的新 Buffer(独立指针) 多线程或不同模块使用同样数据 ❌ slice()
从当前 position 到 limit 的视图子缓冲区 处理部分数据 ❌(子视图)
缓冲区比较
方法名 作用 是否比较内容 说明 equals(Buffer other)
判断两个 Buffer 内容是否相等 ✅ 只比较 剩余内容 ,不比容量等 compareTo(Buffer other)
按字典序比较两个 Buffer 的内容 ✅ 也只比较 剩余内容 ,遵循 Comparable 接口 ==
比较引用是否相同 ❌ 比较的是对象地址
只读缓冲区 ReadOnlyBuffer
public static void main ( String [ ] args) {
int [ ] arr = new int [ ] { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 } ;
IntBuffer buffer = IntBuffer . wrap ( arr) ;
IntBuffer readOnlyBuffer = buffer. asReadOnlyBuffer ( ) ;
while ( readOnlyBuffer. hasRemaining ( ) ) {
System . out. println ( readOnlyBuffer. get ( ) ) ;
}
arr[ 0 ] = 100 ;
readOnlyBuffer. rewind ( ) ;
while ( readOnlyBuffer. hasRemaining ( ) ) {
System . out. println ( readOnlyBuffer. get ( ) ) ;
}
}
BypeBuffer
和CharBuffer
项目 ByteBuffer
CharBuffer
存储单位 byte
(1字节)char
(2字节,UTF-16)常见用途 网络/文件读写、序列化、通用原始数据 处理字符串、字符编码 数据长度单位 字节 字符(2字节) 编码处理 常配合 CharsetDecoder
/CharsetEncoder
可直接处理 Unicode 字符 可否转换 可用 .asCharBuffer()
创建视图 可通过编码转成 ByteBuffer
ByteBuffer buf = ByteBuffer . allocate ( 10 ) ;
buf. put ( ( byte ) 65 ) ;
buf. flip ( ) ;
System . out. println ( buf. get ( ) ) ;
CharBuffer cbuf = CharBuffer . allocate ( 10 ) ;
cbuf. put ( '你' ) ;
cbuf. put ( '好' ) ;
cbuf. flip ( ) ;
System . out. println ( cbuf. get ( ) ) ;
Charset charset = StandardCharsets . UTF_8;
ByteBuffer byteBuf = charset. encode ( "你好" ) ;
CharBuffer charBuf = charset. decode ( byteBuf) ;
System . out. println ( charBuf. toString ( ) ) ;
直接缓冲区
对比项 直接缓冲区 (allocateDirect
) 普通缓冲区 (allocate
) 内存位置 堆外(OS内存) JVM 堆内 是否被 GC 管理 ❌ 不受 GC 控制 ✅ 会被 GC 管理 IO 性能 快(省一次复制) 慢(数据需从堆拷贝到内核) 分配/释放成本 高(申请释放慢) 低 是否可访问底层数组 ❌ hasArray()
返回 false ✅ 可用 array()
方法
普通缓冲区:
[Channel] ←→ [内核缓冲区] ←→ [JVM堆缓冲区] ←→ [你的代码]
直接缓冲区:
[Channel] ←→ [内核缓冲区] ←→ [堆外缓冲区] ←→ [你的代码]
场景 是否推荐使用直接缓冲区 文件读取/写入 ✅ 是 网络 socket 数据传输 ✅ 是 临时变量、小数据 ❌ 不推荐(分配成本高) 多次重复使用大数据块 ✅ 非常适合
┌────────────────────────────┐
│ ByteBuffer.allocateDirect() │
└────────────┬───────────────┘
↓
[ JVM 调用 native 方法 ]
↓
[ 分配堆外内存(DirectMemory) ]
↓
[ 创建 DirectByteBuffer 对象 ]
↓
┌──── 使用 ────→ put()/get()/Channel IO ────┐
↓ ↓
[ 只释放 Java 引用 ] [ 等待 GC 回收 ]
↓ ↓
[ Cleaner 自动触发 native free 方法释放内存 ]
阶段 过程 关键点 加载 allocateDirect()
native 分配堆外内存 使用 put/get/channel 读写 不走 JVM 堆,效率高 释放 依赖 GC 和 Cleaner 不可手动释放,不能频繁创建
|
| ---- | -------------------- | -------------------------- | | 加载 | allocateDirect()
| native 分配堆外内存 | | 使用 | put/get/channel 读写 | 不走 JVM 堆,效率高 | | 释放 | 依赖 GC 和 Cleaner | 不可手动释放,不能频繁创建 |