JavaNIO-缓冲区01 Buffer

1 简介

缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。在JVM中将内存分为堆内内存,堆外内存,所谓堆外即不受gc控制,有的时候也被称为缓冲区,和直接缓冲区,为了简便之后都按堆内内存,堆外内存来说。

缓冲区用于和NIO通道进行交互。数据是从通道读入缓冲区,从缓冲区写入到通道中的。

image

2 类结构

Buffer类是一个抽象类,它具有7 个直接子类,分别是ByteBuffer 、CharBuffer 、DoubleBuffer 、FloatBuffer 、IntBuffer 、LongBuffer 、
ShortBuffer,它们同样是抽象类,要实例化一个ByteBuffer需要实例其子类HeapByteBuffer或DirectByteBuffer。其中HeapByteBuffer表示堆内内存,DirectByteBuffer表示堆外内存

image

3 内存管理

Linux中内存被分一块一块的页,而在Java常用管理数据的方式就是数组,数组是一组连续的内存空间,来存储一组具有相同类型的数据,可以通过下标访问数组元素。但由于在Java语言中对数组自身进行操作的API非常少,如果对数组中的数据进行高级处理,需要程序员自己写代码进行实现,处理的方式是比较原始的。而Buffer提供了一种更高效的管理内存数据的方式。它和数组意义可以管理各种类型数据。

工作原理

作为一块内存,一定会存在读写,当我们读取时Buffer需要切换读模式,当我们写入时Buffer需要切换写模式,其内存通过4个指针来管理内存,当我们申请一块内存缓冲区必须指定其容量,切换写模式每次往缓冲区写入对应类型数据时,其内部会存在一个指针position会伴随写入向后移动,用来表示当前写入的位置。当然缓存区数据容量是有限的当position移动到capacity时在往缓冲区写入数据会抛出数组越界。切换读模式每次从缓冲区读取数据对应类型数据时,其内部会存在一个指针position会伴随写入向后移动,用来表示当前读取的位置,当当position移动到capacity时在往缓冲区读取数据会发现读取失败。有时我们需要对缓冲区中读写做限制,这时可以设置limit,这样读取写入的数据不能操作limit指针指向的位置。有时候我们需要对某个位置做标记,方便在某个时候返回标记,这时我们可以设置mark

image

Buffer源码定义

public abstract class Buffer {

    ...省略代码

    // Invariants: mark <= position <= limit <= capacity
    private int mark = -1;
    private int position = 0;
    private int limit;
    private int capacity;

    long address;

    Buffer(int mark, int pos, int lim, int cap) {       // package-private
        if (cap < 0)
            throw new IllegalArgumentException("Negative capacity: " + cap);
        /** 设置capacity **/    
        this.capacity = cap;
        limit(lim);
        position(pos);
        if (mark >= 0) {
            if (mark > pos)
                throw new IllegalArgumentException("mark > position: ("
                                                   + mark + " > " + pos + ")");
            this.mark = mark;
        }
    }
    /** 设置limit **/
    public final Buffer limit(int newLimit) {
        if ((newLimit > capacity) || (newLimit < 0))
            throw new IllegalArgumentException();
        limit = newLimit;
        if (position > limit) position = limit;
        if (mark > limit) mark = -1;
        return this;
    }
    
    /** 设置position **/
    public final Buffer position(int newPosition) {
        if ((newPosition > limit) || (newPosition < 0))
            throw new IllegalArgumentException();
        position = newPosition;
        if (mark > position) mark = -1;
        return this;
    }
    

从上面我们得出如下结论 0<=mark<=position<=imit<=capacity

简单案例

@Test
public void testBuffer() {
    //申请一块内存
    ByteBuffer allocate = ByteBuffer.allocate(10);
    System.out.println(allocate);
    //写入数据
    allocate.put((byte) 1);
    allocate.put((byte) 2);
    System.out.println(allocate);
    //切换读模式
    allocate.flip();
    //读取数据
    System.out.println(allocate);
    System.out.println(allocate.get());
    System.out.println(allocate.get());
}

java.nio.HeapByteBuffer[pos=0 lim=10 cap=10]
java.nio.HeapByteBuffer[pos=2 lim=10 cap=10]
java.nio.HeapByteBuffer[pos=0 lim=2 cap=10]
1
2    

4 Buffer API 操作

image
4.1 申请一块缓冲区

Buffer.java 类是抽象类, 并不能直接实例化,
而其子类: ByteBuffer 、CharBuffer 、DoubleBuffi町、FloatBuff1町、
lntBuffer 、LongBuffer 和ShortBuffer 也是抽象类,也无法实例化,他们核心作用是为子类提供工厂构造函数和通用逻辑实现这里我们已ByteBuffer为例子

使用allocate申请一块内存

/** 申请一块堆内内存Buffer **/
public static ByteBuffer allocate(int capacity) {
    if (capacity < 0)
        throw new IllegalArgumentException();
    return new HeapByteBuffer(capacity, capacity);
}
 
/** 申请一块堆外内存Buffer **/    
public static ByteBuffer allocateDirect(int capacity) {
        return new DirectByteBuffer(capacity);
}

使用数组实现,实例化Bufferr

/** 使用数组实现,实例化Buffer 
*  offset 表示数组管理起始位置
*  length 表示管理从起始位置开始数据长度
**/    
public static ByteBuffer wrap(byte[] array,
                                    int offset, int length)
{
    try {
        return new HeapByteBuffer(array, offset, length);
    } catch (IllegalArgumentException x) {
        throw new IndexOutOfBoundsException();
    }
}
 
/** 使用数组实现,实例化Buffer **/      
public static ByteBuffer wrap(byte[] array) {
    return wrap(array, 0, array.length);
}    

这里之所以说使用数组实现,实例化Bufferr,是因为ByteBuffer 、CharBuffer 、DoubleBuffi町、FloatBuff1町、
lntBuffer 、LongBuffer 和ShortBuffer都是通过数组来管理内存,我们下面以ByteBuffer为例看代码。

public abstract class ByteBuffer
    extends Buffer
    implements Comparable<ByteBuffer>
{
    /*** 内存使用数组存储数据 **/
    final byte[] hb;
    /**  数组首元素位置 **/
    final int offset;
    /**  是否只读 **/
    boolean isReadOnly;             

    /** 
    *  mark 标记位置
       pos  position标记位置
       lim  limit标记位置
       cap  capacity标记位置
    **/
    ByteBuffer(int mark, int pos, int lim, int cap,   // package-private
                 byte[] hb, int offset)
    {
        super(mark, pos, lim, cap);
        this.hb = hb;
        this.offset = offset;
    }

    
    ByteBuffer(int mark, int pos, int lim, int cap) { // package-private
        this(mark, pos, lim, cap, null, 0);
    }

简单案例

  • 使用数组为参数构造Buffer时 缓冲区中的capacity=arry.length,limit=arry.length
  • 当使用wrap(byte[] array,int offset, int length) position=offset
  • 当使用wrap(byte[] array) position=0
   @Test
    public void testBuffer_wrap() {

        byte[] byteArray = new byte[]{1, 2, 3};
        short[] shortArray = new short[]{1, 2, 3, 4};
        int[] intArray = new int[]{1, 2, 3, 4, 5};
        long[] longArray = new long[]{1, 2, 3, 4, 5, 6};
        float[] floatArray = new float[]{1, 2, 3, 4, 5, 6, 7};
        double[] doubleArray = new double[]{1, 2, 3, 4, 5, 6, 7, 8};
        char[] charArray = new char[]{'a', 'b', 'c', 'd'};

        /** *Buffer.wrap提供了Heap*Buffer的工厂方法  **/
        ByteBuffer byteBuffer = ByteBuffer.wrap(byteArray);
        ByteBuffer byteBuffer2 = ByteBuffer.wrap(byteArray,1,2);
        ShortBuffer shortBuffer = ShortBuffer.wrap(shortArray);
        IntBuffer intBuffer = IntBuffer.wrap(intArray);
        LongBuffer longBuffer = LongBuffer.wrap(longArray);
        FloatBuffer floatBuffer = FloatBuffer.wrap(floatArray);
        DoubleBuffer doubleBuffer = DoubleBuffer.wrap(doubleArray);
        CharBuffer charBuffer = CharBuffer.wrap(charArray);

        System.out.println("byteBuffer=" + byteBuffer.getClass().getName());
        System.out.println("shortBuffer=" + shortBuffer.getClass().getName());
        System.out.println("intBuffer=" + intBuffer.getClass().getName());
        System.out.println("longBuffer=" + longBuffer.getClass().getName());
        System.out.println("floatBuffer=" + floatBuffer.getClass().getName());
        System.out.println("doubleBuffer=" + doubleBuffer.getClass().getName());
        System.out.println("charBuffer=" + charBuffer.getClass().getName());

        System.out.println();

        System.out.println("byteBuffer.=" + byteBuffer);
        System.out.println("byteBuffer2.=" + byteBuffer2);
        System.out.println("shortBuffer.=" + shortBuffer);
        System.out.println("intBuffer.=" + intBuffer);
        System.out.println("longBuffer.=" + longBuffer);
        System.out.println("floatBuffer.=" + floatBuffer);
        System.out.println("doubleBuffer.=" + doubleBuffer);
        System.out.println("charBuffer.=" + charBuffer);
    }

byteBuffer=java.nio.HeapByteBuffer
shortBuffer=java.nio.HeapShortBuffer
intBuffer=java.nio.HeapIntBuffer
longBuffer=java.nio.HeapLongBuffer
floatBuffer=java.nio.HeapFloatBuffer
doubleBuffer=java.nio.HeapDoubleBuffer
charBuffer=java.nio.HeapCharBuffer

byteBuffer.=java.nio.HeapByteBuffer[pos=0 lim=3 cap=3]
byteBuffer2.=java.nio.HeapByteBuffer[pos=1 lim=3 cap=3]
shortBuffer.=java.nio.HeapShortBuffer[pos=0 lim=4 cap=4]
intBuffer.=java.nio.HeapIntBuffer[pos=0 lim=5 cap=5]
longBuffer.=java.nio.HeapLongBuffer[pos=0 lim=6 cap=6]
floatBuffer.=java.nio.HeapFloatBuffer[pos=0 lim=7 cap=7]
doubleBuffer.=java.nio.HeapDoubleBuffer[pos=0 lim=8 cap=8]
charBuffer.=abcd   
4.2 限制获取与设置

设置limit逻辑

  • 1 newLimit不能大于capacity,newLimit不能小于0
  • 2 如果position小于limit,将position移动到limit处
  • 3 如果mark大于limit,mark被取消
/** 返回limit **/
public final int limit() {
        return limit;
}

/** 设置limit **/
public final Buffer limit(int newLimit) {
    /** newLimit不能大于capacity,newLimit不能小于0 **/
    if ((newLimit > capacity) || (newLimit < 0))
        throw new IllegalArgumentException();
    limit = newLimit;
    /** 如果position小于limit,将position移动到limit处 **/
    if (position > limit) position = limit;
    /** 如果mark大于limit,mark被取消 **/
    if (mark > limit) mark = -1;
    return this;
}

案例

    @Test
    public void testBuffer_limit() {
        ByteBuffer buffer = ByteBuffer.allocate(6);
        System.out.println(buffer);
        buffer.limit(3);
        System.out.println();
        System.out.println(buffer);
        buffer.put((byte) 1);
        buffer.put((byte) 2);
        buffer.put((byte) 3);
        buffer.put((byte) 4);  //BufferOverflowException


        byte[] byteArray = new byte[]{1,2,3,4,5,6};
        ByteBuffer buffer2 = ByteBuffer.wrap(byteArray);
        System.out.println(buffer2);
        buffer2.limit(3);
        System.out.println();
        System.out.println(buffer2);
        System.out.println(buffer2.get());
        System.out.println(buffer2.get());
        System.out.println(buffer2.get());
        System.out.println(buffer2.get()); //BufferUnderflowException
    }
4.3 位置获取与设置

设置position逻辑

  • 1 newPosition不能大于limit,newPosition不能小于0
  • 3 如果mark大于position,mark被取消
/** 返回position **/
public final int position() {
        return position;
}


/** 返回position **/
public final Buffer position(int newPosition) {
    if ((newPosition > limit) || (newPosition < 0))
        throw new IllegalArgumentException();
    position = newPosition;
    if (mark > position) mark = -1;
    return this;
}

案例

 @Test
    public void testBuffer_position() {
        /** 写入 **/
        ByteBuffer buffer = ByteBuffer.allocate(6);
        buffer.put((byte) 1);
        buffer.put((byte) 2);
        System.out.println(buffer);
        buffer.position(0);
        System.out.println(buffer);
        buffer.put((byte) 3);
        buffer.put((byte) 4);  //BufferOverflowException
        for (int i = 0; i < buffer.array().length; i++) {
            System.out.println(buffer.array()[i] + " ");
        }
        System.out.println("-------------------------");
        /** 读取 **/
        byte[] byteArray = new byte[]{1,2,3,4,5,6};
        ByteBuffer buffer2 = ByteBuffer.wrap(byteArray);
        System.out.println(buffer2.get());
        System.out.println(buffer2.get());
        System.out.println(buffer2);
        buffer.position(0);
        System.out.println(buffer2);
        System.out.println(buffer2.get());
        System.out.println(buffer2.get());
    }

java.nio.HeapByteBuffer[pos=2 lim=6 cap=6]
java.nio.HeapByteBuffer[pos=0 lim=6 cap=6]
3 
4 
0 
0 
0 
0 
-------------------------
1
2
java.nio.HeapByteBuffer[pos=2 lim=6 cap=6]
java.nio.HeapByteBuffer[pos=2 lim=6 cap=6]
3
4
    
4.4 剩余空间大小获取
public final int remaining() {
        return limit - position;
    }


public final boolean hasRemaining() {
    return position < limit;
}

案例

    @Test
    public void testBuffer_remaining() {
        /** 写入 **/
        ByteBuffer buffer = ByteBuffer.allocate(6);
        buffer.put((byte) 1);
        System.out.println(buffer);
        System.out.println(buffer.remaining());
        buffer.put((byte) 2);
        System.out.println(buffer);
        System.out.println(buffer.remaining());

        System.out.println("-------------------------");
        /** 读取 **/
        byte[] byteArray = new byte[]{1,2,3,4,5,6};
        ByteBuffer buffer2 = ByteBuffer.wrap(byteArray);
        buffer2.get();
        System.out.println(buffer2);
        System.out.println(buffer2.remaining());
        buffer2.get();
        System.out.println(buffer2);
        System.out.println(buffer2.remaining());
    }

java.nio.HeapByteBuffer[pos=1 lim=6 cap=6]
5
java.nio.HeapByteBuffer[pos=2 lim=6 cap=6]
4
-------------------------
java.nio.HeapByteBuffer[pos=1 lim=6 cap=6]
5
java.nio.HeapByteBuffer[pos=2 lim=6 cap=6]
4    
4.5 处理标记
/**
 * 在此位置设置此缓冲区的标记。
 */
public final Buffer mark() {
    mark = position;
    return this;
}

/**
 * 将position位置重置为先前标记的位置。
 */
public final Buffer reset() {
    int m = mark;
    if (m < 0)
        throw new InvalidMarkException();
    position = m;
    return this;
}

案例

 @Test
    public void testBuffer_mark() {
        /** 写入 **/
        ByteBuffer buffer = ByteBuffer.allocate(6);
        buffer.mark();
        buffer.put((byte) 1);
        buffer.put((byte) 2);
        System.out.println(buffer);
        buffer.reset();
        buffer.put((byte) 3);
        buffer.put((byte) 4);
        for (int i = 0; i < buffer.array().length; i++) {
            System.out.println(buffer.array()[i] + " ");
        }

        System.out.println("-------------------------");
        /** 读取 **/
        byte[] byteArray = new byte[]{1,2,3,4,5,6};
        ByteBuffer buffer2 = ByteBuffer.wrap(byteArray);
        buffer2.mark();
        System.out.println(buffer2.get());
        System.out.println(buffer2.get());
        System.out.println(buffer2);
        buffer2.reset();
        System.out.println(buffer2);
        System.out.println(buffer2.get());
        System.out.println(buffer2.get());
    }

java.nio.HeapByteBuffer[pos=2 lim=6 cap=6]
3 
4 
0 
0 
0 
0 
-------------------------
1
2
java.nio.HeapByteBuffer[pos=2 lim=6 cap=6]
java.nio.HeapByteBuffer[pos=0 lim=6 cap=6]
1
2    
4.6 判断只读

判断缓冲区是否只读Buffer定义为模板方法,我们前面知道ByteBuffer 、CharBuffer 、DoubleBuffi町、FloatBuff1町、
lntBuffer 、LongBuffer 和ShortBuffer内部是通过管理数组来管理内存,因而会覆盖此方法返回false

//Buffer判断只读
public abstract boolean isReadOnly();

//ByteBuffer实现
public boolean isReadOnly() {
    return false;
}

案例

@Test
    public void testBuffer_isRead() {
        byte[] byteArray = new byte[]{1, 2, 3};
        short[] shortArray = new short[]{1, 2, 3, 4};
        int[] intArray = new int[]{1, 2, 3, 4, 5};
        long[] longArray = new long[]{1, 2, 3, 4, 5, 6};
        float[] floatArray = new float[]{1, 2, 3, 4, 5, 6, 7};
        double[] doubleArray = new double[]{1, 2, 3, 4, 5, 6, 7, 8};
        char[] charArray = new char[]{'a', 'b', 'c', 'd'};

        /** *Buffer.wrap提供了Heap*Buffer的工厂方法  **/
        ByteBuffer byteBuffer = ByteBuffer.wrap(byteArray);
        ShortBuffer shortBuffer = ShortBuffer.wrap(shortArray);
        IntBuffer intBuffer = IntBuffer.wrap(intArray);
        LongBuffer longBuffer = LongBuffer.wrap(longArray);
        FloatBuffer floatBuffer = FloatBuffer.wrap(floatArray);
        DoubleBuffer doubleBuffer = DoubleBuffer.wrap(doubleArray);
        CharBuffer charBuffer = CharBuffer.wrap(charArray);

        System.out.println("byteBuffer=" + byteBuffer.isReadOnly());
        System.out.println("byteBuffer=" + shortBuffer.isReadOnly());
        System.out.println("byteBuffer=" + intBuffer.isReadOnly());
        System.out.println("byteBuffer=" + longBuffer.isReadOnly());
        System.out.println("byteBuffer=" + floatBuffer.isReadOnly());
        System.out.println("byteBuffer=" + doubleBuffer.isReadOnly());
        System.out.println("byteBuffer=" + charBuffer.isReadOnly());
    }

byteBuffer=false
byteBuffer=false
byteBuffer=false
byteBuffer=false
byteBuffer=false
byteBuffer=false
byteBuffer=false    

4.7 判断是否是直接缓冲区

/** 判断是否是直接缓冲区,模板方法,子类实现 **/
public abstract boolean isDirect();


//HeapByteBuffer实现
public boolean isDirect() {
    return false;
}
    
//DirectByteBuffer实现
public boolean isDirect() {
    return true;
}    

案例

@Test
    public void testBuffer_isDirect() {
        System.out.println(ByteBuffer.allocate(10).isDirect());
        System.out.println(ByteBuffer.allocateDirect(10).isDirect());
    }

false
true    
4.8 还原缓冲区的状态

将缓冲区还原到初始状态,这里只是改变其中的指针并没有清理数据

    public final Buffer clear() {
        position = 0;
        limit = capacity;
        mark = -1;
        return this;
    }

案例

    @Test
    public void testBuffer_clear() {
        /** 读取 **/
        byte[] byteArray = new byte[]{1,2,3,4,5,6};
        ByteBuffer buffer2 = ByteBuffer.wrap(byteArray);
        buffer2.limit(3);
        System.out.println(buffer2);
        System.out.println(buffer2.get());
        buffer2.clear();
        System.out.println(buffer2);
        System.out.println(buffer2.get());
    }

java.nio.HeapByteBuffer[pos=0 lim=3 cap=6]
1
java.nio.HeapByteBuffer[pos=0 lim=6 cap=6]
1    
4.9 切换读写模式

position 设置为0
limit 设置为position

public final Buffer flip() {
    limit = position;
    position = 0;
    mark = -1;
    return this;
}

案例

@Test
public void testBuffer() {
    //申请一块内存
    ByteBuffer allocate = ByteBuffer.allocate(10);
    System.out.println(allocate);
    //写入数据
    allocate.put((byte) 1);
    allocate.put((byte) 2);
    System.out.println(allocate);
    //切换读模式
    allocate.flip();
    //读取数据
    System.out.println(allocate);
    System.out.println(allocate.get());
    System.out.println(allocate.get());
}

java.nio.HeapByteBuffer[pos=0 lim=10 cap=10]
java.nio.HeapByteBuffer[pos=2 lim=10 cap=10]
java.nio.HeapByteBuffer[pos=0 lim=2 cap=10]
1
2    
4.10 是否数组实现

是否数组实现在Buffer是模板方法,是由子类实现,前面说了ByteBuffer 、CharBuffer 、DoubleBuffi町、FloatBuff1町、
lntBuffer 、LongBuffer 和ShortBuffer,使用warp都是使用数组实现

//是否数组实现
public abstract boolean hasArray();


//ByteBuffer实现
public final boolean hasArray() {
    return (hb != null) && !isReadOnly;
}

案例

@Test
public void testBuffer_hasArray(){
    /** 读取 **/
    byte[] byteArray = new byte[]{1,2,3,4,5,6};
    ByteBuffer buffer2 = ByteBuffer.wrap(byteArray);
    System.out.println(buffer2.hasArray());
}
4.11 重绕缓冲区

和clear不同的是并不修改limit

public final Buffer rewind() {
        position = 0;
        mark = -1;
        return this;
    }

案例

@Test
    public void testBuffer_rewind(){
        /** 读取 **/
        byte[] byteArray = new byte[]{1,2,3,4,5,6};
        ByteBuffer buffer2 = ByteBuffer.wrap(byteArray);
        buffer2.limit(3);
        System.out.println(buffer2);
        System.out.println(buffer2.get());
        buffer2.rewind();
        System.out.println(buffer2);
        System.out.println(buffer2.get());
    }

java.nio.HeapByteBuffer[pos=0 lim=3 cap=6]
1
java.nio.HeapByteBuffer[pos=0 lim=3 cap=6]
1    
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,717评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,501评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,311评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,417评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,500评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,538评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,557评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,310评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,759评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,065评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,233评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,909评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,548评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,172评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,420评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,103评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,098评论 2 352

推荐阅读更多精彩内容

  • 转自 http://www.ibm.com/developerworks/cn/education/java/j-...
    抓兔子的猫阅读 2,299评论 0 22
  • Java NIO主要解决了Java IO的效率问题,解决此问题的思路之一是利用硬件和操作系统直接支持的缓冲区、虚拟...
    小波同学阅读 687评论 0 1
  • Java NIO中的Buffer用于和NIO通道进行交互。数据是从通道读入缓冲区,从缓冲区写入到通道中的。缓冲区本...
    桥头放牛娃阅读 2,908评论 0 5
  • 一 Buffer(缓冲区)介绍 1.1Buffer本质上就是一块内存区,可以用来写入数据,并在稍后读取出来。这块内...
    hedgehog1112阅读 261评论 0 0
  • 以 Buffer 类开始我们对 java.nio 软件包的浏览历程。这些类是 java.nio 的构造基础。在本章...
    沉沦2014阅读 582评论 0 4