DirectByteBuffer 不支持 array() 方法,因其底层使用堆外内存而非 byte[] 数组;必须先调用 hasArray() 判断,为 true 时才可安全使用 array(),否则需通过 get() 复制数据。

因为 DirectByteBuffer 没有底层可访问的 byte[] 数组,array() 方法在设计上就明确不支持堆外内存缓冲区。
根本原因:堆内 vs 堆外内存实现不同
ByteBuffer 是抽象类,实际运行时是它的两个子类之一:
-
HeapByteBuffer:用普通 Java 堆内存(
byte[])实现,array()返回的就是这个数组,可直接读写; -
DirectByteBuffer:通过 JNI 在 JVM 堆外分配内存(如 C 的 malloc),内部没有
byte[],array()无数组可返回,所以强制抛出 UnsupportedOperationException。
安全调用的前提:必须先检查 hasArray()
Java 文档明确要求:不能无条件调用 array()。正确做法是先判断缓冲区是否支持:
- 调用
buffer.hasArray()—— 返回 true 才表示底层有可用数组; - 仅当为 true 时,才可安全调用
buffer.array()和buffer.arrayOffset(); - 如果为 false(比如 DirectByteBuffer 或只读包装缓冲区),就必须换其他方式获取数据。
替代方案:绕过 array() 获取字节数组
当 hasArray() 为 false 时,推荐以下通用做法:
- 用
new byte[buffer.remaining()]创建目标数组; - 调用
buffer.get(byteArray)将当前 position 到 limit 的内容复制进去; - 注意:该操作会移动 position,若需保持原状态,可先
buffer.duplicate().get(...); - 框架中常用工具类替代,例如 Netty 的
ByteBufUtil.getBytes(buf)或Unpooled.copiedBuffer(buf)。
常见触发场景
这些情况容易误用 array() 导致异常:
- 使用
ByteBuffer.allocateDirect(1024)创建缓冲区后直接调用array(); - Netty 默认使用堆外内存,
ByteBufAllocator.DEFAULT.buffer()返回的 buffer 多数是 DirectByteBuffer; - 某些 WebSocket 或 NIO 框架底层自动选用 DirectBuffer 提升性能,但业务代码仍按 HeapBuffer 逻辑写;
- Android 不同版本对 ByteBuffer 实现策略不一致,部分机型默认走 Direct 分配。
不复杂但容易忽略:只要记住 array() 不是“通用取数组”方法,而是“取底层数组引用”的快捷通道——有才有,没有就别强求。










