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

xiaoxiao2021-02-28  87

转载请注明出处:http://blog.csdn.net/linxdcn/article/details/72896616


1 概述

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

BufferChannelSelectors

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

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


2 Buffer类

Buffer类是一个抽象类,所有的XxxBuffer均继承此类。Buffer类的作用跟BufferedReader和BufferedInputStream类中的缓冲区作用是一样的。只不过线程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,用于备份当前的positionposition:初始值为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类型

ByteBufferCharBufferDoubleBufferFloatBufferIntBufferLongBufferShortBufferMappedByteBuffer

其中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

转载请注明原文地址: https://www.6miu.com/read-34231.html

最新回复(0)