java.nio.Buffer属性及方法

缓冲区由当前的多个线程使用是不安全的。如果一个缓冲区由不止一个线程使用,则应该通过适当的同步来控制对该缓冲区的访问。

 

缓冲区有以下四个属性:

  • capacity (容量):缓冲区的容量是它所包含的元素的数量。缓冲区的容量永远不会为负并且从不会更改。
  • limit (限制):缓冲区的限制是不应读取或写入的第一个元素的索引。缓冲区的限制永远不会为负,并且永远不会大于其容量。
  • position (位置):缓冲区的位置是下一个要读取或写入的元素的索引。缓冲区的位置永远不会为负,并且永远不会大于其限制。
  • mark (标记):缓冲区的标记是在调用reset 方法时其位置将被重置到该mark位置。如果定义的标记后,位置(position)或限制(limit)调整为小于标记的值时,该标记将被丢弃。如果未定义标记,则调用 reset 方法将导致抛出InvalidMarkException。

传输数据定义了两种get和put操作:
相对操作 :操作读取或写入从当前位置开始的一个或多个元素,然后将该位置增加传输的元素的数量。
绝对操作 :操作采用显式元素索引,不会影响位置。

 

四属性之间的关系
0 <= 标记(mark) <= 位置(position) <= 限制(limit) <= 容量(capacity)

 

新创建的缓冲区位置为零(position = 0)和标记未定义(mark = -1)。初始限制可以为零,也可以是其他某个值,这取决于缓冲区类型及其构建方式。一般情况下,缓冲区的初始内容未定义。

 

clear() 清除此缓冲区。将位置设置为零,限制设置为该容量,并且丢弃标记。 源码:
 position = 0;
 limit = capacity;
 mark = -1;

在get或put操作填充此缓冲区之前调用此方法。例如:
buf.clear();     // 准备写
in.read(buf);    // 读取

注:此方法并没有实际擦除缓冲区中的数据。

 

flip() 反转此缓冲区。首先将当前位置设置为限制,然后将该位置设置为零。如果已定义了标记,则丢弃该标记。源码如下:
 limit = position;
 position = 0;
 mark = -1;

在缓冲读取或put操作之后,调用此方法以做好缓冲写入或相对get操作。例如:
buf.put(magic);    // 预置报头
in.read(buf);      // 从输入通道中读取数据并紧跟在报送后存放
buf.flip();        // 准备读
out.write(buf);    // 把头与体写到输出通道

当将数据从一个地方传输到另一个地方时,经常将此方法与compact方法一起使用。

 

rewind() 重置此缓冲区。将位置设置为零并丢弃标记。 源码如下:
 position = 0;
 mark = -1;

在缓冲重新写入或get操作之前调用此方法(假定已经适当设置了限制)。例如:
out.write(buf);     // 剩余数据写入输出通道
buf.rewind();      // 重绕
buf.get(array);    // 复制数据到array

 

mark() 在此缓冲区的位置设置其标记, 把mark设为position 。源码如下:
mark = position;

 

reset() 将此缓冲区的位置重新设置成以前标记的位置。 调用此方法既不会更改也不会丢弃标记的值。 源码如下:
position = mark;

 

 

其他方法:

capacity() 返回buffer的capacity(容量)


limit() :返回此缓冲区的限制 limit的值

 

limit(int lim) :设置limit的值。


position() :返回此缓冲区的位置
position

 

position(int pos) :设置position的值。


remaining() :返回当前位置与限制之间的元素数量
(limit - position)

 

hasRemaining() :如果position和limit之间还有数据,就返回true。

这是一个非常经典的 Java NIO 相关问题,Buffer 类是 Java NIO 系统中的一个核心类,它是一个抽象类,定义了许多抽象方法和一些常用的方法。在实际开发过程中,我们经常会使用到 Buffer 相关的 API,其中包括三个常用的函数:slice()、duplicate() 和 wrap()。 - slice():创建一个与原始缓冲区共享数据的新缓冲区,可以理解成是原始缓冲区的一个视图,二者共享数据。新缓冲区的容量是原始缓冲区的剩余元素数量,位置是原始缓冲区当前位置,限制是原始缓冲区的剩余元素数量,标记被忽略。这个方法的主要作用就是将原始缓冲区的一个子区域作为一个新的缓冲区来使用,这个新的缓冲区与原始缓冲区数据共享,所以对新缓冲区的操作也会对原始缓冲区产生影响。 示例代码: ``` ByteBuffer buffer = ByteBuffer.allocate(10); for (int i = 0; i < buffer.capacity(); i++) { buffer.put((byte) i); } buffer.position(2); buffer.limit(6); ByteBuffer sliceBuffer = buffer.slice(); for (int i = 0; i < sliceBuffer.capacity(); i++) { byte b = sliceBuffer.get(i); b *= 11; sliceBuffer.put(i, b); } buffer.position(0); buffer.limit(buffer.capacity()); while (buffer.hasRemaining()) { System.out.println(buffer.get()); } ``` 输出结果为: ``` 0 1 22 33 44 5 6 7 8 9 ``` - duplicate():创建一个原始缓冲区的副本,这个副本与原始缓冲区共享数据,但是它拥有自己的索引、标记、限制和容量等属性,对副本的修改不会影响到原始缓冲区。这个方法的主要作用就是复制一个原始缓冲区,用于多线程操作或者备份。 示例代码: ``` ByteBuffer buffer = ByteBuffer.allocate(10); for (int i = 0; i < buffer.capacity(); i++) { buffer.put((byte) i); } ByteBuffer duplicateBuffer = buffer.duplicate(); for (int i = 0; i < duplicateBuffer.capacity(); i++) { byte b = duplicateBuffer.get(i); b *= 11; duplicateBuffer.put(i, b); } buffer.position(0); buffer.limit(buffer.capacity()); while (buffer.hasRemaining()) { System.out.println(buffer.get()); } ``` 输出结果为: ``` 0 1 2 3 4 5 6 7 8 9 ``` - wrap():创建一个包装了给定数组的缓冲区,这个缓冲区的容量是给定数组的长度,位置为 0,限制为数组的长度,标记被忽略。这个方法的主要作用就是将一个数组包装成缓冲区,从而可以使用缓冲区提供的方法对数组进行操作。 示例代码: ``` byte[] bytes = new byte[10]; for (int i = 0; i < bytes.length; i++) { bytes[i] = (byte) i; } ByteBuffer buffer = ByteBuffer.wrap(bytes); for (int i = 0; i < buffer.capacity(); i++) { byte b = buffer.get(i); b *= 11; buffer.put(i, b); } for (byte b : bytes) { System.out.println(b); } ``` 输出结果为: ``` 0 11 22 33 44 55 66 77 88 99 ``` 以上就是 slice()、duplicate() 和 wrap() 函数的作用和区别,以及示例代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值