您的位置:首页 > Web前端

【Java8源码分析】NIO包-Buffer类:ByteBuffer与HeapByteBuffer(一)

2017-06-07 22:31 781 查看
转载请注明出处:http://blog.csdn.net/linxdcn/article/details/72896616

1 概述

Java NIO 由以下几个核心部分组成:

Buffer

Channel

Selectors



相关类的使用方法可以参考Java NIO 系列教程,写的通俗易懂。

本文主要从源码方面分析一下Buffer类

2 Buffer类

Buffer类是一个抽象类,所有的XxxBuffer均继承此类。Buffer类的作用跟BufferedReaderBufferedInputStream类中的缓冲区作用是一样的。只不过线程Buffer独立出来,而且添加了更多的功能。

2.1 构造函数

public abstract class Buffer {

private int mark = -1;
private int position = 0;
private int limit;
private int capacity;

// 在 direct buffers 中使用
long address;

Buffer(int mark, int pos, int lim, int cap) {
if (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;
}
}
}


各属性变量的含义如下:

mark:初始值为-1,用于备份当前的position

position:初始值为0。position表示当前可以写入或读取数据的位置。当写入或读取一个数据后, position向前移动到下一个位置。

limit:

写模式下,limit表示最多能往Buffer里写多少数据,等于capacity值。

读模式下,limit表示最多可以读取多少数据。

capacity:缓存数组大小



2.2 主要方法

//返回容量
public final int capacity() {
return capacity;
}

// 返回当前位置
public final int position() {
return position;
}

//返回临界值
public final int limit() {
return limit;
}

//记录当前位置
public final Buffer mark() {
mark = position;
return this;
}

//恢复到之前记录位置
public final Buffer reset() {
int m = mark;
if (m < 0)
throw new InvalidMarkException();
position = m;
return this;
}

//清除缓冲区,即恢复变量的初始位置,但不清除缓冲区中的内容
public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
}

//由写模式转为读模式
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}

//重置position为0,从头读写数据或读数据
public final Buffer rewind() {
position = 0;
mark = -1;
return this;
}


3 ByteBuffer类

Java NIO 有以下Buffer类型

ByteBuffer

CharBuffer

DoubleBuffer

FloatBuffer

IntBuffer

LongBuffer

ShortBuffer

MappedByteBuffer

其中MappedByteBuffer的实现比较特殊,其余各对应一种基础数据类型的缓冲区,实现原理是差不多的,下面以ByteBuffer为例介绍。

ByteBuffer也是一个抽象类,它的实现类有HeapByteBuffer和DirectByteBuffer两种。

HeapByteBuffer:是在jvm虚拟机的堆上申请内存空间

DirectByteBuffer:是直接在物理内存中申请内存空间

3.1 Buffer的分配

要想获得一个Buffer对象首先要进行分配。 每一个Buffer类都有一个allocate方法。

// 堆上面的分配
public static ByteBuffer allocate(int capacity) {
if (capacity < 0)
throw new IllegalArgumentException();
return new HeapByteBuffer(capacity, capacity);
}

// 直接在物理内存上分配
public static ByteBuffer allocateDirect(int capacity) {
return new DirectByteBuffer(capacity);
}


3.2 ByteBuffer的读写

从ByteBuffer中读写数据有两种方式(其余Buffer类也一样):

通过Channel类的
read
write
函数从Buffer中读写(后续Channel中介绍)

ByteBuffer的
get
put
函数

public abstract byte get();

public abstract byte get(int index);

public abstract ByteBuffer put(byte b);

public abstract ByteBuffer put(int index, byte b);


3.2 Compact函数

ByteBuffer类比基类Buffer多了Compact函数,
compact()
方法将所有未读的数据拷贝到Buffer起始处。然后将position设到最后一个未读元素正后面。
limit
属性依然像
clear()
方法一样,设置成
capacity
。现在Buffer准备好写数据了,但是不会覆盖未读的数据。

public abstract ByteBuffer compact();


3.3 HeapByteBuffer子类

HeapByteBuffer是ByteBuffer的实现子类,内部是通过byte数组实现在堆上的缓冲区,其余的
get
put
compact
函数均通过数组下标操作实现,比较简单,源码就不列了。

protected final byte[] hb;

HeapByteBuffer(int cap, int lim) {

super(-1, 0, lim, cap, new byte[cap], 0);

}

HeapByteBuffer(byte[] buf, int off, int len) {

super(-1, off, off + len, buf.length, buf, 0);

}


3.4 DirectByteBuffer子类

DirectByteBuffer是在jvm堆外直接申请一块空间,其把文件映射到该内存空间中,与MappedByteBuffer较为类似,在特大文件的读写方面效率非常高。由于比较特殊,将在下一篇详细介绍。

(未完,待续)

参考

http://ifeve.com/java-nio-all/

转载请注明出处:http://blog.csdn.net/linxdcn/article/details/72896616
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: