因为使用通信框架不同的缘故,bytebuffer这种东西在每个框架中都有可能是不同的,比如在Mina中叫IoBuffer,在Netty中叫ByteBuf,虽然叫法不同,但其实用法相似。

有时候为了方便,就直接使用java内置的ByteBuffer了。所以了解ByteBuffer的使用,触类旁通也会变得很容易了。

在一些容易混淆的问题产生之前,先复习一下常用场景下的基本使用。
创建

 public static void main(String[] args) {byte[] bytes = new byte[10];for (int i = 0; i < 10; i++) {bytes[i] = (byte) i;}ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);ByteBuffer byteBuffer = ByteBuffer.allocate(10);}

在实际场景中,wrap的使用可能比较频繁一些,直接传入byte数组即可,如果需要分次传入内容的话,就需要使用allocate先创建一个bytebuffer然后使用put方法写入内容。wrap和allocate相比,好处就在于wrap之后positon的位置是已经重置过了的,直接可以用来读,而不需要使用flip来重置position。
输出

        System.out.println(Arrays.toString(byteBuffer.array()));

可以使用array()输出,但需要注意的是,array()输出的永远是全部内容,也就是bytebuffer中一开始传入的byte数组是什么,输出的就是什么。
读写

     for (int i = 0; i < 10; i++) {byteBuffer.put((byte) i);}byteBuffer.flip();for (int i = 0; i < 10; i++) {byteBuffer.get((byte) i);}byteBuffer.putLong(2L);byteBuffer.flip();byteBuffer.getLong();

读写的话,对应的各种put/get方法,需要注意的就是position所代表的意义就行。每一次读写操作,都会影响到position,position是一个读写操作的当前有效起始位置,可以说是bytebuffer中最需要关注的一个变量。

reset/rewind/clear

reset方法用于重置position为mark值,通常和mark()方法一起用。

    public final Buffer reset() {int m = mark;if (m < 0)throw new InvalidMarkException();position = m;return this;}

比如这样:

 private static void testMark(ByteBuffer byteBuffer){byteBuffer.get();byteBuffer.mark();byteBuffer.get();System.out.println("remain:"+byteBuffer.remaining());byte[] remain1 = new byte[byteBuffer.remaining()];byteBuffer.get(remain1);System.out.println(byteBuffer.toString());System.out.println(Arrays.toString(remain1));System.out.println();byteBuffer.reset();System.out.println("remain:"+byteBuffer.remaining());byte[] remain2 = new byte[byteBuffer.remaining()];byteBuffer.get(remain2);System.out.println(byteBuffer.toString());System.out.println(Arrays.toString(remain2));}

输出:

remain:8
java.nio.HeapByteBuffer[pos=2 lim=10 cap=10]
[2, 3, 4, 5, 6, 7, 8, 9]remain:9
java.nio.HeapByteBuffer[pos=1 lim=10 cap=10]
[1, 2, 3, 4, 5, 6, 7, 8, 9]

mark方法就是标记一个位置,使得reset之后,读写操作又可以从这个位置开始。

而rewind就不管这些了,统统从0开始。

    public final Buffer rewind() {position = 0;mark = -1;return this;}

rewind本身的意思就是“倒带,重来”的意思,相比之下,比reset更像“重置”。

clear则更进一步,将limit也重置为原始值也就是capacity值。

    public final Buffer clear() {position = 0;limit = capacity;mark = -1;return this;}

从这几个方法也可以看出所谓的mark<=position<=limit<=capacity是怎么来的。

flip

flip相比之下有些特殊,它通常用于将要开始读写的状态之前,比如一个bytebuffer刚刚写入了一些内容,这时候position还在最大值,也就是写入内容的最后一位,此时开始读内容肯定是不可以的,因为在这个position之后是没有内容可读的了。

    public final Buffer flip() {limit = position;position = 0;mark = -1;return this;}

此时想要进行读操作,就必须把position重置,这也是flip常常在读操作或写操作完毕后使用的缘故,更多地是代表着一种“进入下一状态”的意思。

position

作为一个“游标”,只听说它会变,至于怎么变,倒从来没见识过。还是看源码:

//HeapByteBuffer.javapublic ByteBuffer put(byte x) {hb[ix(nextPutIndex())] = x;return this;}protected int ix(int i) {return i + offset;}//Buffer.javafinal int nextPutIndex() {                          // package-privateif (position >= limit)throw new BufferOverflowException();return position++;}

写入字节是position每次自增,而写入其他数据类型则同样是在调用nextPutIndex方法,只不过不是自增1了而是根据数据类型来定,比如putLong就是增加8:

//HeapByteBuffer.javapublic ByteBuffer putLong(long x) {Bits.putLong(this, ix(nextPutIndex(8)), x, bigEndian);return this;}//Bits.javastatic void putLong(ByteBuffer bb, int bi, long x, boolean bigEndian) {if (bigEndian)putLongB(bb, bi, x);elseputLongL(bb, bi, x);}static void putLongB(ByteBuffer bb, int bi, long x) {bb._put(bi    , long7(x));bb._put(bi + 1, long6(x));bb._put(bi + 2, long5(x));bb._put(bi + 3, long4(x));bb._put(bi + 4, long3(x));bb._put(bi + 5, long2(x));bb._put(bi + 6, long1(x));bb._put(bi + 7, long0(x));}private static byte long7(long x) { return (byte)(x >> 56); }private static byte long6(long x) { return (byte)(x >> 48); }private static byte long5(long x) { return (byte)(x >> 40); }private static byte long4(long x) { return (byte)(x >> 32); }private static byte long3(long x) { return (byte)(x >> 24); }private static byte long2(long x) { return (byte)(x >> 16); }private static byte long1(long x) { return (byte)(x >>  8); }private static byte long0(long x) { return (byte)(x      ); }void _put(int i, byte b) {                  // package-privatehb[i] = b;}

好吧,看起来是有点眼花,个人觉得这里其实可以用循环一次解决的。类似这种方法:

     for (int i = 0; i < 8; i++) {bb._put(bi + (7 - i), x >> ((7 - i) * 8));}

不过可能是由于这样一眼很难看出在干什么吧(?)。
所以put其他类型的数据,也是同样的道理。

HeapByteBuffer

在上面创建的bytebuffer,默认都是HeapByteBuffer。
比如:

    public static ByteBuffer wrap(byte[] array,int offset, int length){try {return new HeapByteBuffer(array, offset, length);} catch (IllegalArgumentException x) {throw new IndexOutOfBoundsException();}}

又比如:

    public static ByteBuffer allocate(int capacity) {if (capacity < 0)throw new IllegalArgumentException();return new HeapByteBuffer(capacity, capacity);}

它们使用了不同的构造方法,但都使用了同样的父类构造方法:

    HeapByteBuffer(int cap, int lim) {            // package-privatesuper(-1, 0, lim, cap, new byte[cap], 0);/*hb = new byte[cap];offset = 0;*/}HeapByteBuffer(byte[] buf, int off, int len) { // package-privatesuper(-1, off, off + len, buf.length, buf, 0);/*hb = buf;offset = 0;*/}//ByteBuffer.javaByteBuffer(int mark, int pos, int lim, int cap,   // package-privatebyte[] hb, int offset){super(mark, pos, lim, cap);this.hb = hb;this.offset = offset;}//Buffer.javaBuffer(int mark, int pos, int lim, int cap) {       // package-privateif (cap < 0)throw new IllegalArgumentException("Negative capacity: " + cap);this.capacity = cap;limit(lim);position(pos);if (mark >= 0) {if (mark > pos)throw new IllegalArgumentException("mark > position: ("+ mark + " > " + pos + ")");this.mark = mark;}}public final Buffer limit(int newLimit) {if ((newLimit > capacity) || (newLimit < 0))throw new IllegalArgumentException();limit = newLimit;if (position > limit) position = limit;if (mark > limit) mark = -1;return this;}public final Buffer position(int newPosition) {if ((newPosition > limit) || (newPosition < 0))throw new IllegalArgumentException();position = newPosition;if (mark > position) mark = -1;return this;}

所以,在正常的情况下,一个bytebyffer被创建后,

mark = -1;
position = 0;
limit = array.length = capacity;

只要弄清楚这几者的关系,bytebuffer就可以放心使用了。

ByteBuffer注意事项相关推荐

  1. 整理自《Pro Java 7 NIO.2》

     http://developer.51cto.com/art/200911/165703.htm http://developer.51cto.com/art/201112/307728.htm ...

  2. 使用堆内内存HeapByteBuffer的注意事项

    分享一个很多人容易踩的一个坑:HeapByteBuffer 的使用问题.我们都知道 NIO 分装了 ByteBuffer 接口,使得 filechannel 的文件 IO API 变得非常的简单.By ...

  3. 内存heap_哪个内存更快?Heap或ByteBuffer或Direct?

    内存heap Java正在成为新的C / C ++,它被广泛用于开发高性能系统. 对像我这样的数百万Java开发人员来说非常好! 在这个博客中,我将分享我可以用Java完成的不同类型的内存分配的实验, ...

  4. 哪个内存更快?Heap或ByteBuffer或Direct?

    Java正在成为新的C / C ++,它被广泛用于开发高性能系统. 对像我这样的数百万Java开发人员来说非常好! 在这个博客中,我将分享我可以用Java完成的不同类型的内存分配实验以及您从中获得的好 ...

  5. C++ OP相关注意事项

    C++ OP相关注意事项 Paddle中Op的构建逻辑 1.Paddle中Op的构建逻辑 Paddle中所有的Op都继承自OperatorBase,且所有的Op都是无状态的,每个Op包含的成员变量只有 ...

  6. Hashing散列注意事项

    Hashing散列注意事项 Numba支持内置功能hash(),只需__hash__()在提供的参数上调用成员函数即可 .这使得添加对新类型的哈希支持变得微不足道,这是因为扩展APIoverload_ ...

  7. android 读取asset下的文件注意事项

    注意事项:file:后面是三个斜杠,后面是android_asset,在后面就是html的名字.

  8. Djang1.8+Python2.0迁移到Django2.0+Python3.6注意事项(转)

    Djang1.8+Python2.0迁移到Django2.0+Python3.6注意事项 参考:https://blog.csdn.net/weixin_40475396/article/detail ...

  9. 【整理】NSTimer使用及注意事项

    一.NSTimer的创建 // 创建一个定时器,但是么有添加到运行循环,我们需要在创建定时器后手动的调用 NSRunLoop 对象的 addTimer:forMode: 方法. + (NSTimer ...

最新文章

  1. 中消协上午发布报告 跨境电商假货等仍旧是毛病
  2. hiveserver2启动不起来_汽车一键启动只能用来打火吗 车主必须知道的几个“隐藏”技巧!...
  3. Java递归一个四十万的树结构_java递归展示树形图代码实现以及遇到的问题
  4. python3.7 keras和tensorflow兼容_解决Keras 与 Tensorflow 版本之间的兼容性问题
  5. python3--环境搭建说明;
  6. 分享100个好看且实用的JavaScript特效
  7. 第七届“泰迪杯”——个人总结吧
  8. 初始vue脚手架的项目文件中mian.js文件
  9. 数据结构PTA 进阶实验5-3.2 新浪微博热门话题(分离链接法 )
  10. vue-amap 根据地址 查询经纬度
  11. python语料库_NLPPython笔记——语料库
  12. Worktile 中百万级实时消息推送服务的实现
  13. 服务器上Ubuntu系统安装
  14. 毒液:致命守护者HDTC1080清晰英语中字
  15. js函数 argements参数
  16. Primavera Unifier 19.12.X Patch/Update(补丁/更新)
  17. LSTM预测算法(股票预测 天气预测 房价预测)
  18. 直播平台必备-百度音视频直播 LSS
  19. 使用Verilog语言实现时间计数器
  20. 【POJ1474】监控摄像头 半平面交

热门文章

  1. 卷积码matlab图,【卷积码的MATLAB仿真设计】 卷积码仿真
  2. scrollTop、offsetTop、clientTop
  3. MS17-010 Eternal Blue(永恒之蓝)”, 修复补丁下载汇总地址!
  4. 【Java学习全家桶】1460道Java热门问题,阿里百位技术专家答疑解惑
  5. 会员电商直播+供应链+云平台吸引客户购买解决销售困难
  6. 2017二级c语言考试大纲,2017年计算机等级考试二级C语言程序设计考试大纲
  7. 第四周项目5——猴子选大王
  8. 教育直播开发形式怎样?
  9. .NET之降龙十八掌
  10. 在cmd下用cd命令进不了D盘的问题