我报名参加金石方案1期挑战——分割10万奖池,这是我的第4篇文章,点击查看活动详情

Java网络开发的过程中触摸NIO是必不可少的,在NIO中有一个重要的组件那就是 ByteBuffer ,下面就来通过图文的方式来讲解ByteBuffer的运用以及一些操作的原理。

1. ByteBuffer完成原理

对于ByteBuffer来说首要有五个重要属性如下:

  • mark(int类型): 记载当前索引的方位
  • position(int类型): 读形式:表明接下来能够读取的数据方位, 写形式:表明能够写入数据的方位
  • limit(int类型): 读形式:表明能够写入数据巨细,写形式:表明能够写入数据巨细。 默许是ByteBuffer的capacity
  • capacity(int类型): ByteBuffer的容量
  • hb(byte array): 实际数据存储byte数组

Tips: 几个数据之间的巨细联系mark <= position <= limit <= capacity

示意图如下:

Java NIO ByteBuffer原理使用图文详解

2. 读写形式

ByteBuffer首要有读写形式,Java原生的和Netty的ByteBuf有不同的。ByteBuffer的读写形式需要自己进行切换。

2.1 写形式

写形式示意图如下:

Java NIO ByteBuffer原理使用图文详解

从上图能够看出来初始化后capacity是固定了。limit的值能够进行设置。当有新的数据写入position指针会进行移动。能写入的数据由limit确认。

2.2 读形式

读形式示意图如下:

Java NIO ByteBuffer原理使用图文详解

如何把写入的数据读取出来,首先要将写形式转化成成读的形式。否则会读形式会在在写的指针往后进行读取。随着数据读取position指针也会进行移动,limit会约束指针移动的方位。

Tips: flip 方法用于读写形式切换

对于ByteBuffer首要是弄清楚四个变量 position、limit、mark、capacity 四者之间的联系转化以及读写的联系转化。

3. 运用示例

下面会结合例子以及示图来说明ByteBuffer的一些基本运用和一些常见API的操作。如下是一个简略的运用示例:

public class ByteBufferExample {
    public static void main(String[] args) {
        ByteBuffer allocate = ByteBuffer.allocate(20); //分配一个巨细为20bytes的ByteBuffer
        System.out.println(allocate.capacity()); //20
        System.out.println(allocate.limit()); // 20
        System.out.println(allocate.position()); //0
        System.out.println("--------------------");
        allocate.putLong(10L); 
        System.out.println(allocate.capacity());//20
        System.out.println(allocate.limit());//20
        System.out.println(allocate.position());//8
        System.out.println("--------------------");
        System.out.println(allocate.getLong());
        System.out.println(allocate.capacity());//20
        System.out.println(allocate.limit());//20
        System.out.println(allocate.position());//16
    }
}

不同的变量变化的示意图如下:

Java NIO ByteBuffer原理使用图文详解

上面代码中没有进行读写形式转化的。position指针不论读仍是写会一直往capacity方位接近。

3.1 flip-API

运用示例代码如下:

    public static void main(String[] args) throws Exception{
        ByteBuffer allocate = ByteBuffer.allocate(20); //分配一个巨细为20bytes的ByteBuffer
        allocate.putLong(10L);
        System.out.println(allocate.capacity()); //20
        System.out.println(allocate.limit()); // 20
        System.out.println(allocate.position()); //8
        System.out.println("--------------------");
        allocate.flip();
        System.out.println(allocate.capacity()); //20
        System.out.println(allocate.limit()); // 8
        System.out.println(allocate.position()); //0
        System.out.println("--------------------");
        System.out.println(allocate.getLong()); //10
        System.out.println(allocate.capacity()); //20
        System.out.println(allocate.limit()); // 8
        System.out.println(allocate.position()); //8
        allocate.putLong(10L); //throw exception
    }

示意图如下:

Java NIO ByteBuffer原理使用图文详解

从上面示意图能够看出调用方法 flip 的时分会将写入时分回的position指针的值赋给limit一起重置position的值到0的方位。这儿就完成了读写的形式转化。假如再次读取的时分就能够将写入到ByteBuffer的值读取出来。

方法flip首要用于读写形式的切换

Tips: 假如你调用flip方法后读取的数据或许写入的数据超过了limit会有过错抛出

3.2 mark-API

运用代码如下:

    public static void main(String[] args) throws Exception{
        ByteBuffer allocate = ByteBuffer.allocate(20); //分配一个巨细为20bytes的ByteBuffer
        allocate.putLong(10L);
        allocate.putInt(1);
        allocate.mark();
        System.out.println(allocate.capacity());//20
        System.out.println(allocate.limit());//20
        System.out.println(allocate.position());//12
        System.out.println("-----------------------");
        allocate.getLong();
        System.out.println(allocate.capacity());//20
        System.out.println(allocate.limit());//20
        System.out.println(allocate.position());//20
        allocate.reset();
        System.out.println("-----------------------");
        System.out.println(allocate.capacity());//20
        System.out.println(allocate.limit());//20
        System.out.println(allocate.position());//12
    }

示意图如下:

Java NIO ByteBuffer原理使用图文详解

从上图能够知道调用 mark 是将position的值赋给mark属性。然后你进行接下来的继续读写操作。当你需要将position恢复到标记字段的时分调用**reset** 进行恢复。

Tips: 假如你调用mark然后有调用了flip,flip会将mark进行重置。

3.3 compact-API

运用代码实例如下:

public static void main(String[] args) throws Exception{
    ByteBuffer allocate = ByteBuffer.allocate(20); //分配一个巨细为20bytes的ByteBuffer
    allocate.putLong(10L);
    allocate.flip();
    allocate.getInt();
    System.out.println(allocate.capacity());//20
    System.out.println(allocate.limit());//8
    System.out.println(allocate.position());//4
    allocate.compact();
    System.out.println("----------------------");
    System.out.println(allocate.capacity());//20
    System.out.println(allocate.limit());//20
    System.out.println(allocate.position());//4
}

示意图如下:

Java NIO ByteBuffer原理使用图文详解

从上图能够看出来 compact 的首要效果:用来清楚掉当前position指针之前的数据然后将指针指向limit的方位一起将整个指针往左移动直到替换掉position左面的数据,与此一起还会将limit的值设置为capacity。

4. 总结

ByteBuffer总体运用起来和Netty的ByteBuf对比没有Netty ByteBuf好用。但是对于运用原生的Java NIO的开发来说也是能够的。首要是需要用户自己对读写进行转化等操作,运用起来比较繁琐。但是整个ByteBuffer的完成仍是比较简略的。

我是蚂蚁背大象,文章对你有协助点赞关注我,文章有不正确的当地请您指正留言评论~谢谢! 大家能够Follow我的GitHub mxsm