duplicate() 创建共享底层数据的浅拷贝缓冲区,容量、limit、position、mark初始相同但状态独立,修改状态互不影响,修改数据则彼此可见,非线程安全。

duplicate() 方法创建的是共享底层数据的浅拷贝缓冲区,不是复制一份新数组,而是让两个 Buffer 对象指向同一块内存区域。 它适用于需要多个独立操作视角(比如不同线程读写不同位置、或预处理与主流程分离)但又不想额外分配内存的场景。
duplicate 的核心行为
调用 buffer.duplicate() 后,新缓冲区:
- 与原缓冲区共享同一份底层数据(如
char[]、long[]或直接内存地址) - 容量(capacity)、限制(limit)、位置(position)、标记(mark)值初始时完全相同
- 但 position、limit、mark 等状态变量彼此独立——修改一个不会影响另一个的状态
- 只读性保持一致:若原 Buffer 是只读的,副本也是只读的;否则都可读写
- 不是线程安全的,多个线程同时操作共享数据需自行加锁
典型使用示例
以下以 CharBuffer 为例说明实际效果:
CharBuffer original = CharBuffer.allocate(6);
original.put("Hello".toCharArray()); // 写入 5 个字符
original.flip(); // position=0, limit=5
CharBuffer copy = original.duplicate();
System.out.println(copy.remaining()); // 输出 5(初始状态一致)
original.get(); // 读一个字符,original.position 变为 1
System.out.println(copy.position()); // 仍为 0(copy 的 position 未变)
copy.put('X'); // 在 copy 的 position=0 处写入 'X'
System.out.println(original.get(0)); // 输出 'X'(底层数据被改,original 也能看到)
和其它复制方法的区别
对比常见 Buffer 复制方式,避免误用:
- slice():只共享从当前 position 到 limit 的子区间,新缓冲区 capacity = limit − position,且 position 始终为 0
- asReadOnlyBuffer():返回只读副本,即使原 Buffer 可写,副本也无法调用 put 类方法
- wrap() 或 allocate + put():真正复制数据(深拷贝),内存开销大,但完全隔离
- duplicate():零拷贝、轻量、状态独立、数据共享——适合临时视图切换
注意事项
使用 duplicate 时需特别留意:
- 不要在 duplicate 出来的缓冲区上调用
array()后再修改原缓冲区内容,除非你明确知道它们共用数组且已同步处理 - 如果原缓冲区是 direct buffer(堆外内存),duplicate 返回的仍是 direct buffer,且仍通过相同地址访问数据
- 调用
clear()、flip()、rewind()等方法只影响调用者的状态,不影响副本 - 对数据本身的修改(如
put(int index, T value)或通过array()修改)会跨副本可见
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











