• java nio之Buffer(一)


    Buffer是一个包装了基本数据元素数组的对象,它以及它的子类定义了一系列API用于处理数据缓存。

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

    四者关系:0 <= mark <= position <= limit <= capacity

    二、API

    package java.nio;
    public abstract class Buffer {
    public final int capacity( )
    public final int position( )
    public final Buffer position (int newPosition)
    public final int limit( )
    public final Buffer limit (int newLimit)
    public final Buffer mark( )
    public final Buffer reset( )
    public final Buffer clear( )
    public final Buffer flip( )
    public final Buffer rewind( )
    public final int remaining( )
    public final boolean hasRemaining( )
    public abstract boolean isReadOnly( );
    }

    支持链式调用,如:buffer.mark().position(5).reset( );
    注意isReadOnly()方法决定了buffer是否可写。

    三、操作
      以ByteBuffer为例,
    1、访问,通过get(),get(index),其中get()从当前position位置读取,get(index)从index位置读取,不改变当前position,下面要说到的put也一样。
    2、填充,通过put(byte),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)。
  • 相关阅读:
    HTML
    HTML
    HTML
    HTML
    HTML
    HTML
    HTML
    TOMCAT-IDEA远程debug方法
    调整mysql数据库最大连接数
    win10开机时内存使用率达到99%以上
  • 原文地址:https://www.cnblogs.com/marcotan/p/4256980.html
Copyright © 2020-2023  润新知