bytebuffer.asreadonlybuffer()创建共享底层数组的只读视图,状态独立但不隔离数据,put操作被禁止而get仍可读取;其只读性仅限该实例,无法防止其他可写引用修改原始数据。

ByteBuffer.asReadOnlyBuffer() 创建的是原缓冲区的只读视图,不复制底层数据,所有位置、限制、标记等状态独立,但共享同一块字节数组。它不能防止底层数据被其他可写引用修改,仅阻止通过该只读缓冲区执行 put 操作。
只读视图的核心特性
调用 asReadOnlyBuffer() 后返回的新缓冲区:
- 与原缓冲区共享 同一个 backing array(如果存在),即底层 byte[] 不会拷贝
- 自己的 position、limit、mark、capacity 等属性独立维护,修改它们不影响原缓冲区
- 所有 put 方法均抛出 ReadOnlyBufferException,包括 put(byte)、put(int, byte)、put(byte[]) 等
- get 方法、hasArray()、arrayOffset() 等读取相关操作完全可用
为什么不能“保护”原始数据?
只读性仅作用于该缓冲区实例本身,而非内存数据。常见误区是认为它能锁定数据:
- 若原 ByteBuffer 是 heap buffer(由 byte[] 支撑),且你仍持有该数组引用或可写缓冲区,仍可修改内容
- 若原缓冲区后续调用 put(),只读视图中通过 get() 读到的值会同步变化
- 只读缓冲区调用 duplicate() 或 slice() 得到的仍是只读的,但同样不隔离数据
适用场景与正确用法
该方法适用于需要向外提供“不可篡改接口”,同时又想避免数据拷贝开销的场景:
- 框架/SDK 向上层返回缓冲区时,用 asReadOnlyBuffer() 明确语义:你可读,但不该改
- 多线程中传递只读视图,配合 final 字段 + 不泄露可写引用,可减少同步需求
- 调试或日志打印前生成只读副本,避免误调 put 干扰业务逻辑流
- 注意:如需真正隔离数据,应使用 ByteBuffer.allocate(n).put(original).flip() 做深拷贝
一个典型误用对比
以下代码看似安全,实则仍有风险:
ByteBuffer data = ByteBuffer.allocate(10).put(new byte[]{1,2,3});
ByteBuffer safeView = data.asReadOnlyBuffer();
// ✅ 下面这行会抛异常:safeView.put((byte)99);
// ❌ 但下面这行仍会改变 safeView 中能读到的数据:
data.put(0, (byte)88); // 修改索引 0,safeView.get(0) 接着就读到 88
真正安全需确保:原缓冲区不再被写入,或根本不再持有可写引用。










