文档章节

Java Nio Buffer

猪刚烈
 猪刚烈
发布于 2014/09/24 13:52
字数 1422
阅读 8
收藏 0

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

Buffer是特定基本类型元素的线性有限序列,它以及它的子类定义了一系列API用于处理数据缓存。



一、属性
Buffer有四个基本属性:
1、capacity:  容量,buffer能够容纳的最大元素数目,在Buffer创建时设定并不能更改
2、limit: buffer中有效位置数目
3、position: 下一个读或者写的位置
4、mark:  用于记忆的标志位,配合reset()使用,初始值未设定,调用mark后将当前position设为值

不变式
标记、位置、限制和容量值遵守以下不变式:
0 <= 标记 <= 位置 <= 限制 <= 容量

二、API  
public final int capacity( ) 返回此缓冲区的容量。
public final int position() 返回此缓冲区的位置。
public final Buffer position(int newPosition) 设置此缓冲区的位置。如果mark已定义且大于新的位置,则丢弃该标记。
public final int limit( ) 返回此缓冲区的限制。
public final Buffer limit (int newLimit) 设置此缓冲区的限制。
public final Buffer mark( ) 在此缓冲区的位置设置标记。
public final Buffer reset( ) 将此缓冲区的位置重置为以前mark的位置。
public final Buffer clear( ) 清除此缓冲区。将position设置为 0,将limit设置为容量,并丢弃mark。 
public final Buffer flip( ) 为读做好准备。它将limit设置为当前位置,然后将position设置为 0。如果已定义了标记,则丢弃该标记。
public final Buffer rewind( ) 一般flip()只能被执行一次,想第二次执行flip(),请使用rewind()。它使limit保持不变,将position设置为 0 ,并丢弃mark。
public final int remaining( ) 返回当前位置与限制之间的元素数。
public final boolean hasRemaining( ) 告知在当前位置和限制之间是否有元素。
public abstract boolean isReadOnly( ) 告知此缓冲区是否为只读缓冲区。



三、操作(以ByteBuffer为例)

1、访问:
get(),从当前position位置读取
get(index),从index位置读取,不改变当前position,下面要说到的put也一样。

2、填充:
put(byte),在当前position位置填充
put(index,byte),按照绝对位置填充不改变当前position属性

3、flipping,试想,我们将填充完毕的buffer传递给socket输出,那么socket读取是依据position属性确定,就会从结尾后一位开始读,这样肯定是不正确的,如果要正确的读取我们先要:
buffer.limit(buffer.position( )).position(0);
将limit设为position, 将position设为0,这个操作就叫flipping,API直接提供了这个操作:  buffer.flip( );

特别注意,flip()方法会改变limit属性,将limit属性从capacity设置为当前position。
rewind()方法与flip()类似,但是仅将position设为0,而不改变limit,通常用于重新读取已经被flip的buffer。
flip()另一个注意点是,两次调用buffer的flip方法,将使得position和limit属性都为0。

4、迭代取元素:

for (int i = 0; buffer.hasRemaining( ), i++) {
myByteArray [i] = buffer.get( );
}

int count = buffer.remaining( );
for (int i = 0; i < count, i++) {
myByteArray [i] = buffer.get( );
}
 


ByteBuffer不是线程安全的,前一种方式适合并发访问,后一种方式效率更高。这两种方式都是一个一个取,效率都比批量取低。


5.clear()方法,将buffer重设为空状态,也就是设置limit=capacity,position=0,以便重复利用。

6.compact()方法,用于压缩buffer,这个方法在多次重复调用时是比较低效。

7.mark(),初始是未定义的,这适合如果调用reset将抛出InvalidMarkException。调用makr()后,将当前position设为mark以便reset时返回。注意,rewind( ), clear( ), and flip( )方法都将丢弃已经创建的mark。调用limit(index),positioon(index),如果index的值小于当前mark,mark也将被丢弃。

8.比较,可以通过equals()和compateTo()方法来比较两个buffer,前一个返回boolean,后一个返回0,-1,1。两个buffer equal的条件是:
1)类型相同
2)剩余元素的数目相等
3)剩余元素也一一相等

9、批量移动数据,为了更有效地进行数据传送,批量的数据存取肯定是不能少的,Buffer及其子类都有提供类似的方法,比如CharBuffer:

public CharBuffer get (char [] dst)
public CharBuffer get (char [] dst, int offset, int length)
public final CharBuffer put (char[] src)
public CharBuffer put (char [] src, int offset, int length)
public CharBuffer put (CharBuffer src)
public final CharBuffer put (String src)
public CharBuffer put (String src, int start, int end)
 



四、创建Buffer
    Buffer以及其子类都无法直接new,而必须把通过他们提供的工厂方法来创建。通常有两种方式:
1、allocate,例如
CharBuffer charBuffer = CharBuffer.allocate (100);
将在堆上分配一个可以存储100个字符的数组作为backing store。

2、wrap,包装一个已有的数组:
char [] myArray = new char [100];
CharBuffer charbuffer = CharBuffer.wrap (myArray);
注意,这样的方式创建的Buffer,将不会在堆上创建新的数组,而是直接利用myArray做backing store,这意味着任何对myArray或者buffer的修改都将影响到buffer或者myArray。可以通过public final boolean hasArray( )方法来判断是否拥有一个数组,通过array()方法取得这个数组。

五、复制Buffer
   其实这个复制也是“浅拷贝”,通过duplicate()方法将返回一个新创建的buffer,这个新buffer与原来的Buffer共享数据,一样的capacity,但是有自己的position、limit和mark属性。通过asReadOnlyBuffer()方法复制的buffer与duplicate()类似,但是是只读的,不能调用put。比较特别的是slice()方法,故名思议,类似切割一个Buffer出来,与duplicate类似,但是它将从原来Buffer的当前position开始,并且capacity等于原来Buffer的剩余元素数目,也就是(limit-position)。


转自:http://www.blogjava.net/killme2008/archive/2008/02/22/181357.html

本文转载自:http://elf8848.iteye.com/blog/1543978

猪刚烈

猪刚烈

粉丝 22
博文 708
码字总数 110
作品 1
海淀
程序员
私信 提问
JAVA NIO编程入门(一)

JAVA NIO编程入门(一) 一、前言 笔者之前接触的NIO编程比较少,所以对这一块的基础也比较弱,NIO作为java编程中一个重要的模块,不能很好的掌握它,感觉自己在java方面就掌握的不够,所以,...

木木匠
2018/09/01
199
0
Java NIO 系列教程 -- delete

(一) Java NIO 概述 Java NIO 由以下几个核心部分组成: Channels Buffers Selectors 虽然Java NIO 中除此之外还有很多类和组件,但在我看来,Channel,Buffer 和 Selector 构成了核心的A...

数据之美
2013/06/09
0
4
JAVA NIO(转)

Java NIO(New IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API。本系列教程将有助于你学习和理解Java NIO。感谢并发编程网的翻译和投递。 (关注ITeye官微,随时...

北极之北
2016/01/16
337
0
Java NIO系列教程(一) Java NIO 概述

Java NIO 由以下几个核心部分组成: Channels Buffers Selectors 虽然Java NIO 中除此之外还有很多类和组件,但在我看来,Channel,Buffer 和 Selector 构成了核心的API。其它组件,如Pipe和...

只想一个人静一静
2014/02/22
96
0
6. 彤哥说netty系列之Java NIO核心组件之Buffer

——日拱一卒,不期而至! 你好,我是彤哥,本篇是netty系列的第六篇。 简介 上一章我们一起学习了Java NIO的核心组件Channel,它可以看作是实体与实体之间的连接,而且需要与Buffer交互,这...

彤哥读源码
12/03
39
0

没有更多内容

加载失败,请刷新页面

加载更多

在C语言中“静态”是什么意思?

我已经在C代码的不同地方看到了static一词。 这就像C#中的静态函数/类(实现在对象之间共享)吗? #1楼 多文件变量作用域示例 在这里,我说明了静态如何影响多个文件中函数定义的范围。 交流...

javail
4分钟前
2
0
利用 FC + OSS 快速搭建 Serverless 实时按需图像处理服务

作者:泽尘 简介 随着具有不同屏幕尺寸和分辨率设备的爆炸式增长,开发人员经常需要提供各种尺寸的图像,从而确保良好的用户体验。目前比较常见的做法是预先为一份图像存放多份具有不同尺寸的...

阿里巴巴云原生
6分钟前
1
0
前端架构最佳实践

Folders-by-Feature Structure 胜过 Folders-by-Type Structure

lilugirl
17分钟前
3
0
Seata AT 模式启动源码分析

从上一篇文章「分布式事务中间件Seata的设计原理」讲了下 Seata AT 模式的一些设计原理,从中也知道了 AT 模式的三个角色(RM、TM、TC),接下来我会更新 Seata 源码分析系列文章。今天就来分...

后端进阶
18分钟前
3
0
Python中“自我”一词的目的是什么?

Python中self词的目的是什么? 我知道它是指从该类创建的特定对象,但是我看不到为什么要将它显式地作为参数添加到每个函数中。 为了说明这一点,在Ruby中,我可以这样做: class myClass ...

技术盛宴
20分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部