Java NIO ByteBuffer详解

java Socket读写缓存区Writer和Reader: http://donald-draper.iteye.com/blog/2356885
前一篇文章中,我们讲了java Socket io的Writer和Reader,在上一篇中,在流解码器和编码器中,经常用到字节缓冲ByteBuffer,今天我们就来看一ByteBuffer。
ByteBuffer有两个实现一个为,HeapByteBuffer,另一个为DirectByteBuffer,这两个有什么区别呢?
我们引入原文,不翻译以免都是原味;
1.HeapByteBuffer
Java代码   收藏代码
  1. //ByteBuffer,创建方法  
  2.  public static ByteBuffer allocate(int capacity) {  
  3.         if (capacity < 0)  
  4.             throw new IllegalArgumentException();  
  5.         return new HeapByteBuffer(capacity, capacity);  
  6.     }  

HeapByteBuffer使用的java堆内存
2.DirectByteBuffer
Java代码   收藏代码
  1. //ByteBuffer,创建方法  
  2. public static ByteBuffer allocateDirect(int capacity) {  
  3.         return new DirectByteBuffer(capacity);  
  4.     }  
  5. * <p> A byte buffer is either <i>direct</i> or <i>non-direct</i>.  Given a  
  6.  * direct byte buffer, the Java virtual machine will make a best effort to  
  7.  * perform native I/O operations directly upon it.  That is, it will attempt to  
  8.  * avoid copying the buffer's content to (or from) an intermediate buffer  
  9.  * before (or after) each invocation of one of the underlying operating  
  10.  * system's native I/O operations.  
  11.  *  
  12.  * <p> A direct byte buffer may be created by invoking the {@link  
  13.  * #allocateDirect(int) allocateDirect} factory method of this class.  The  
  14.  * buffers returned by this method typically have somewhat higher allocation  
  15.  * and deallocation costs than non-direct buffers.  The contents of direct  
  16.  * buffers may reside outside of the normal garbage-collected heap, and so  
  17.  * their impact upon the memory footprint of an application might not be  
  18.  * obvious.  It is therefore recommended that direct buffers be allocated  
  19.  * primarily for large, long-lived buffers that are subject to the underlying  
  20.  * system's native I/O operations.  In general it is best to allocate direct  
  21.  * buffers only when they yield a measureable gain in program performance.  
  22.  *  
  23.  * <p> A direct byte buffer may also be created by {@link  
  24.  * java.nio.channels.FileChannel#map </code>mapping<code>} a region of a file  
  25.  * directly into memory.  An implementation of the Java platform may optionally  
  26.  * support the creation of direct byte buffers from native code via JNI.  If an  
  27.  * instance of one of these kinds of buffers refers to an inaccessible region  
  28.  * of memory then an attempt to access that region will not change the buffer's  
  29.  * content and will cause an unspecified exception to be thrown either at the  
  30.  * time of the access or at some later time.  


DirectByteBuffer使用的是:the Java virtual machine will make a best effort to
perform native I/O operations directly upon it.
使用时要注意:It is therefore recommended that direct buffers be allocated
primarily for large, long-lived buffers that are subject to the underlying
system's native I/O operations


今天我们只讲HeapByteBuffer,ByteBuffer,Buffer,我们先从测试实例来看
Java代码   收藏代码
  1. public abstract class Buffer {  
  2.   
  3.    // Invariants: mark <= position <= limit <= capacity  
  4.    private int mark = -1;//标记,用于reset函数,是复位position到mark位置  
  5.    private int position = 0;//Buffer缓冲区读写位置  
  6.    private int limit;//读写上限  
  7.    private int capacity;//缓冲区容量  
  8.    }  


mark,position,limit,capacity大小关系:

-1 <= mark <= position <= limit <= capacity;
0<= position <= limit <= capacity;



测试主类:


Java代码   收藏代码
  1.  package socket;  
  2.   
  3. import java.nio.BufferOverflowException;  
  4. import java.nio.ByteBuffer;  
  5. /** 
  6.  * 测试ByteBuffer 
  7.  * @author donald 
  8.  * 2017年2月14日 
  9.  * 下午5:23:32 
  10.  */  
  11. public class TestByteBuffer {  
  12.     private static ByteBuffer byteBuffer = null;  
  13.     public  static void main(String[] args) {  
  14.             /* 以下顺序不要改变*/  
  15.             initByteBuffer();  
  16.             testByte();   
  17.             testChar();   
  18.             testMark();  
  19.             testInt();  
  20.             testFloat();   
  21.             testDouble();  
  22.             testLong();  
  23.             testRemaining();  
  24.             testOverFlow();  
  25.             testReset();  
  26.             testClear();  
  27. //          testCompact();  
  28.     }  
  29.     /** 
  30.      * 初始化缓存空间 
  31.      */  
  32.      public static void initByteBuffer(){  
  33.          byteBuffer  = ByteBuffer.allocate(32);  
  34.          System.out.println("===============init status============");  
  35.          System.out.println("position:"+byteBuffer.position());  
  36.          System.out.println("limit:"+byteBuffer.limit());  
  37.          System.out.println("capacity:"+byteBuffer.capacity());  
  38.       }  
  39.      /** 
  40.       * 测试Byte,占用一个字节 
  41.       */  
  42.      public static void testByte(){  
  43.          System.out.println("===============put byte============");  
  44.          //字节  
  45.          byte bbyte = 102;  
  46.          byteBuffer.put(bbyte);//ByteBuffer  
  47.          byteBuffer.get(0);//byte  
  48.          System.out.println("position:"+byteBuffer.position());  
  49.          System.out.println("limit:"+byteBuffer.limit());  
  50.          System.out.println("capacity:"+byteBuffer.capacity());  
  51.          System.out.println("======get byte:"+byteBuffer.get(0));  
  52.      }  
  53.      /** 
  54.       * 测试Char,占用2个字节 
  55.       */  
  56.      public static void testChar(){  
  57.       System.out.println("===============put char============");  
  58.          //字符  
  59.          char aChar= 'a';  
  60.          byteBuffer.putChar(aChar);  
  61.          System.out.println("position:"+byteBuffer.position());  
  62.          System.out.println("limit:"+byteBuffer.limit());  
  63.          System.out.println("capacity:"+byteBuffer.capacity());  
  64.          System.out.println("======get Char:"+byteBuffer.getChar(1));  
  65.      }  
  66.      /** 
  67.       * 标记位置,以便reset,返回这个标记位置 
  68.       */  
  69.       public static void testMark(){  
  70.           //标记位置  
  71.           byteBuffer.mark();  
  72.           System.out.println("===============mark============");  
  73.           System.out.println("position:"+byteBuffer.position());  
  74.           System.out.println("limit:"+byteBuffer.limit());  
  75.           System.out.println("capacity:"+byteBuffer.capacity());  
  76.       }  
  77.       /** 
  78.        * 测试int,占用4个字节 
  79.        */  
  80.       public static void testInt(){  
  81.           System.out.println("===============put int============");  
  82.           //int  
  83.           int int4 = 4;  
  84.           byteBuffer.putInt(int4);  
  85.           System.out.println("position:"+byteBuffer.position());  
  86.           System.out.println("limit:"+byteBuffer.limit());  
  87.           System.out.println("capacity:"+byteBuffer.capacity());  
  88.           //这里为什么从第三个字节开始读取,因为前面一个字节和一个字符总共三个字节  
  89.           System.out.println("======get int:"+byteBuffer.getInt(3));  
  90.       }  
  91.       /** 
  92.        * 测试float,占用4个字节 
  93.        */  
  94.       public static void testFloat(){  
  95.           System.out.println("===============put float============");  
  96.           //float  
  97.           float float5 = 10;  
  98.           byteBuffer.putFloat(float5);  
  99.           System.out.println("position:"+byteBuffer.position());  
  100.           System.out.println("limit:"+byteBuffer.limit());  
  101.           System.out.println("capacity:"+byteBuffer.capacity());  
  102.           //这里为什么从第7个字节开始读取,因为前面一个字节和一个字符,一个int总共7个字节  
  103.           System.out.println("======get float:"+byteBuffer.getFloat(7));  
  104.       }  
  105.       /** 
  106.        * 测试double,占用8个字节 
  107.        */  
  108.       public static void testDouble(){  
  109.           System.out.println("===============put double============");  
  110.           //double  
  111.           double double6 = 20.0;  
  112.           byteBuffer.putDouble(double6);  
  113.           System.out.println("position:"+byteBuffer.position());  
  114.           System.out.println("limit:"+byteBuffer.limit());  
  115.           System.out.println("capacity:"+byteBuffer.capacity());  
  116.           //这里为什么从第11个字节开始读取,因为前面一个字节和一个字符,一个int,一个float总共11个字节  
  117.           System.out.println("======get double:"+byteBuffer.getDouble(11));  
  118.       }  
  119.       /** 
  120.        * 测试Long,占用8个字节 
  121.        */  
  122.       public static void testLong(){  
  123.           System.out.println("===============put long============");  
  124.           //long  
  125.           long long7 = (long30.0;  
  126.           byteBuffer.putLong(long7);  
  127.           System.out.println("position:"+byteBuffer.position());  
  128.           System.out.println("limit:"+byteBuffer.limit());  
  129.           System.out.println("capacity:"+byteBuffer.capacity());  
  130.           //这里为什么从第19个字节开始读取,因为前面一个字节和一个字符,一个int,一个float,一个double总共19个字节  
  131.           System.out.println("======get long:"+byteBuffer.getLong(19));  
  132.       }  
  133.       /** 
  134.        * 测试字节缓冲的剩余空间函数 
  135.        */  
  136.       public static void testRemaining(){  
  137.           System.out.println("======buffer 剩余空间大小:"+byteBuffer.remaining());  
  138.       }  
  139.       /** 
  140.        * 测试添加元素字节长度,大于剩余空间时的情况 
  141.        */  
  142.       public static void testOverFlow(){  
  143.           /*Exception in thread "main" java.nio.BufferOverflowException 
  144.             at java.nio.Buffer.nextPutIndex(Buffer.java:519) 
  145.             at java.nio.HeapByteBuffer.putLong(HeapByteBuffer.java:417) 
  146.             at socket.TestByteBuffer.main(TestByteBuffer.java:60) 
  147.             超出空间,则抛出BufferOverflowException异常 
  148.             */  
  149.          try{  
  150.            byteBuffer.putLong((long)30.0);  
  151.          }  
  152.          catch(BufferOverflowException e){  
  153.            e.printStackTrace();  
  154.          }  
  155.       }  
  156.       /** 
  157.        * 测试回到标记,position为标记的mark 
  158.        */  
  159.       public static void testReset(){  
  160.          System.out.println("===============reset============");  
  161.           //回到mark标记位置,position为标记的mark  
  162.           byteBuffer.reset();  
  163.           System.out.println("position:"+byteBuffer.position());  
  164.           System.out.println("limit:"+byteBuffer.limit());  
  165.           System.out.println("capacity:"+byteBuffer.capacity());  
  166.           System.out.println("======get  int from mark:"+byteBuffer.getInt(3));  
  167.           //重新,从标记位置put一个int值,原来的内容被覆盖掉  
  168.           int int5 = 5;  
  169.           byteBuffer.putInt(int5);  
  170.           System.out.println("position:"+byteBuffer.position());  
  171.           System.out.println("limit:"+byteBuffer.limit());  
  172.           System.out.println("capacity:"+byteBuffer.capacity());  
  173.           System.out.println("======get int from mark after put new int value:"+byteBuffer.getInt(3));  
  174.       }  
  175.       /** 
  176.        * clear重置position,mark,limit位置,原始缓存区内容并不清掉 
  177.        */  
  178.       public static void testClear(){  
  179.           System.out.println("===============clear============");  
  180.           //clear重置position,mark,limit位置,原始缓存区内容并不清掉  
  181.           byteBuffer.clear();  
  182.           System.out.println("position:"+byteBuffer.position());  
  183.           System.out.println("limit:"+byteBuffer.limit());   
  184.           System.out.println("capacity:"+byteBuffer.capacity());  
  185.           System.out.println("======get int  after clear:"+byteBuffer.getInt(3));  
  186.             
  187.       }  
  188.         
  189.       public static void testCompact(){  
  190.              System.out.println("===============compact============");  
  191.                 /* 
  192.                  * compact操作用于当 
  193.                  *  while (in.read(buf) >= 0 || buf.position != 0) { 
  194.                  *     buf.flip(); 
  195.                  *     out.write(buf); 
  196.                  *     buf.compact();    // In case of partial write 
  197.                  *    } 
  198.                  * 当out发送数据,即读取buf的数据,write方法可能只发送了部分数据,buf里还有剩余, 
  199.                  * 这时调用buf.compact()函数将position与limit之间的数据,copy到buf的0到limit-position,进行压缩(非实际以压缩,只是移动), 
  200.                  * 以便下次 向写入缓存。 
  201.                  */  
  202.                  
  203.                 byteBuffer.compact();  
  204.                 System.out.println("position:"+byteBuffer.position());  
  205.                 System.out.println("limit:"+byteBuffer.limit());  
  206.                 System.out.println("capacity:"+byteBuffer.capacity());  
  207.                 System.out.println("======get int:"+byteBuffer.getInt(3));  
  208.                 System.out.println("===============flip============");  
  209.                /*  
  210.                 * buf.put(magic);    // Prepend header 
  211.                 * in.read(buf);      // Read data into rest of buffer 
  212.                 * buf.flip();        // Flip buffer 
  213.                 * out.write(buf);  
  214.                 * 当in从缓冲中读取数据后,如果想要将缓存中的数据发送出去,则调用buf.flip()函数,limit为当前position,position为0, 
  215.                 * / 
  216. //              byteBuffer.flip(); 
  217.                 System.out.println("===============rewind============"); 
  218.                 /*  
  219.                 * out.write(buf);    // Write remaining data 
  220.                 * buf.rewind();      // Rewind buffer 
  221.                 * buf.get(array);    // Copy data into array</pre></blockquote> 
  222.                 * 当out写出数据,即读取buf的数据后,如果想要从缓存中,从0位置,获取缓存数据,则调用buf.rewind() 
  223.                 */              
  224. //              byteBuffer.rewind();  
  225.                   
  226.         }  
  227.         
  228. }  

注意 main里面方法的调用顺序不要变,第一次测试我们先注释掉testCompact方法,控制台输出:
===============init status============
position:0
limit:32
capacity:32
===============put byte============
position:1
limit:32
capacity:32
======get byte:102
===============put char============
position:3
limit:32
capacity:32
======get Char:a
===============mark============
position:3
limit:32
capacity:32
===============put int============
position:7
limit:32
capacity:32
======get int:4
===============put float============
position:11
limit:32
capacity:32
======get float:10.0
===============put double============
position:19
limit:32
capacity:32
======get double:20.0
===============put long============
position:27
limit:32
capacity:32
======get long:30
======buffer 剩余空间大小:5
java.nio.BufferOverflowException
at java.nio.Buffer.nextPutIndex(Buffer.java:519)
at java.nio.HeapByteBuffer.putLong(HeapByteBuffer.java:417)
at socket.TestByteBuffer.testOverFlow(TestByteBuffer.java:150)
at socket.TestByteBuffer.main(TestByteBuffer.java:24)
===============reset============
position:3
limit:32
capacity:32
======get  int from mark:4
position:7
limit:32
capacity:32
======get int from mark after put new int value:5
===============clear============
position:0
limit:32
capacity:32
======get int  after clear:5
从控制台输出可看出,ByteBuffer的put*和get*(int index)方法不改变mark,limit和capacity的值;put则回改变position的位置,put操作后position的位置为,put操作之前position+length(put 操作数);mark操作会改变mark的值,reset操作,则是将position定位到mark;clear操作并不会清空缓冲空间,而是将position复位0,limit为capacity,mark为-1;remain操作返回的是可用的空间大小为capacity-position;
如put后,超出缓冲区大小,则抛出BufferOverflowException异常。


下面我们将mark,reset和clear注释掉,测试Compact操作如下:
Java代码   收藏代码
  1.     public  static void main(String[] args) {  
  2.             /* 以下顺序不要改变*/  
  3.             initByteBuffer();  
  4.             testByte();   
  5.             testChar();   
  6. //          testMark();  
  7.             testInt();  
  8.             testFloat();   
  9.             testDouble();  
  10.             testLong();  
  11.             testRemaining();  
  12.             testOverFlow();  
  13. //          testReset();  
  14. //          testClear();  
  15.             testCompact();  
  16.     }  


关注控制的compact部分输出:
===============put long============
position:27
limit:32
capacity:32
======get long:30
======buffer 剩余空间大小:5
java.nio.BufferOverflowException
at java.nio.Buffer.nextPutIndex(Buffer.java:519)
at java.nio.HeapByteBuffer.putLong(HeapByteBuffer.java:417)
at socket.TestByteBuffer.testOverFlow(TestByteBuffer.java:150)
at socket.TestByteBuffer.main(TestByteBuffer.java:24)
===============compact============
position:5
limit:32
capacity:32
======get int:4
===============flip============
===============rewind============
从控制台输出可以看出,compact操作一般在一下情况调用,
Java代码   收藏代码
  1. /* 
  2. * compact操作用于当 
  3. *  while (in.read(buf) >= 0 || buf.position != 0) { 
  4. *     buf.flip(); 
  5. *     out.write(buf); 
  6. *     buf.compact();    // In case of partial write 
  7. *    } 
  8. */  

当out发送数据,即读取buf的数据,write方法可能只发送了部分数据,buf里还有剩余,
这时调用buf.compact()函数将position与limit之间的数据,copy到buf的0到limit-position,
进行压缩(非实际以压缩,只是移动),以便下次 向写入缓存。当position与limit之间的数据为空时,则不改变原缓冲区,否则copy相应数据。
//HeapByteBuffer
Java代码   收藏代码
  1. public ByteBuffer compact() {  
  2.   
  3.         System.arraycopy(hb, ix(position()), hb, ix(0), remaining());  
  4.         position(remaining());  
  5.         limit(capacity());  
  6.         discardMark();  
  7.         return this;  
  8.     }  

Java代码   收藏代码
  1. /* 
  2. If <code>src</code> is <code>null</code>, then a 
  3. * <code>NullPointerException</code> is thrown and the destination 
  4. * array is not modified. 
  5. */  
  6. //System  
  7.  public static native void arraycopy(Object src,  int  srcPos,  
  8.                                         Object dest, int destPos,  
  9.                                         int length);  



线面我们来看一下Buffer的相关操作:
Java代码   收藏代码
  1. public abstract class Buffer {  
  2.   
  3.     // Invariants: mark <= position <= limit <= capacity  
  4.     private int mark = -1;  
  5.     private int position = 0;  
  6.     private int limit;  
  7.     private int capacity;  
  8.   
  9.    //返回position  
  10.     public final int position() {  
  11.         return position;  
  12.     }  
  13.     //返回capacity  
  14.     public final int capacity() {  
  15.         return capacity;  
  16.     }  
  17.     //重新定义position位置,如mark位置大于新position,则废弃mark位置  
  18.     public final Buffer position(int newPosition) {  
  19.         if ((newPosition > limit) || (newPosition < 0))  
  20.             throw new IllegalArgumentException();  
  21.         position = newPosition;  
  22.         if (mark > position) mark = -1;  
  23.         return this;  
  24.     }  
  25.     //返回limit  
  26.      public final int limit() {  
  27.         return limit;  
  28.     }  
  29.     //标记位置  
  30.     public final Buffer mark() {  
  31.         mark = position;  
  32.         return this;  
  33.     }  
  34.     //复位position到mark位置  
  35.     public final Buffer reset() {  
  36.         int m = mark;  
  37.         if (m < 0)  
  38.             throw new InvalidMarkException();  
  39.         position = m;  
  40.         return this;  
  41.     }  
  42.     //clear操作并不会清空缓冲空间,而是将  
  43.     //position复位0,limit为capacity,mark为-1;  
  44.     public final Buffer clear() {  
  45.         position = 0;  
  46.         limit = capacity;  
  47.         mark = -1;  
  48.         return this;  
  49.     }  
  50.    /*  
  51.     * buf.put(magic);    // Prepend header 
  52.     * in.read(buf);      // Read data into rest of buffer 
  53.     * buf.flip();        // Flip buffer 
  54.     * out.write(buf);  
  55.     * 当in从缓冲中读取数据后,如果想要将缓存中的数据发送出去, 
  56.     * 则调用buf.flip()函数,limit为当前position,position为0, 
  57.     */  
  58.     public final Buffer flip() {  
  59.         limit = position;  
  60.         position = 0;  
  61.         mark = -1;  
  62.         return this;  
  63.     }  
  64.     /*  
  65.      * out.write(buf);    // Write remaining data 
  66.      * buf.rewind();      // Rewind buffer 
  67.      * buf.get(array);    // Copy data into array</pre></blockquote> 
  68.      * 当out写出数据,即读取buf的数据后,如果想要从缓存中,从0位置,获取缓存数据,则调用buf.rewind() 
  69.      */        
  70.     public final Buffer rewind() {  
  71.         position = 0;  
  72.         mark = -1;  
  73.         return this;  
  74.     }  
  75.     //返回可用空间  
  76.     public final int remaining() {  
  77.         return limit - position;  
  78.     }  
  79.     //废弃标记位置  
  80.     final void discardMark() {                          // package-private  
  81.         mark = -1;  
  82.     }  
  83.     Buffer(int mark, int pos, int lim, int cap) {       // package-private  
  84.         if (cap < 0)  
  85.             throw new IllegalArgumentException("Negative capacity: " + cap);  
  86.         this.capacity = cap;  
  87.         limit(lim);  
  88.         position(pos);  
  89.         if (mark >= 0) {  
  90.             if (mark > pos)  
  91.                 throw new IllegalArgumentException("mark > position: ("  
  92.                                                    + mark + " > " + pos + ")");  
  93.             this.mark = mark;  
  94.         }  
  95.     }  
  96. }  

再来看ByteBuffer
Java代码   收藏代码
  1. public abstract class ByteBuffer  
  2.     extends Buffer  
  3.     implements Comparable<ByteBuffer>  
  4. {  
  5.   
  6.     // These fields are declared here rather than in Heap-X-Buffer in order to  
  7.     // reduce the number of virtual method invocations needed to access these  
  8.     // values, which is especially costly when coding small buffers.  
  9.     //  
  10.     final byte[] hb;  // Non-null only for heap buffers,缓存空间  
  11.     final int offset;  
  12.     boolean isReadOnly;   
  13.      ByteBuffer(int mark, int pos, int lim, int cap,   // package-private  
  14.                  byte[] hb, int offset)  
  15.     {  
  16.         super(mark, pos, lim, cap);  
  17.         this.hb = hb;  
  18.         this.offset = offset;  
  19.     }  
  20. }  

再来看
Java代码   收藏代码
  1. class HeapByteBuffer  
  2.     extends ByteBuffer  
  3. {  
  4.     HeapByteBuffer(byte[] buf, int off, int len) { // package-private  
  5.         super(-1, off, off + len, buf.length, buf, 0);  
  6.         /* 
  7.         hb = buf; 
  8.         offset = 0; 
  9.         */  
  10.     }  
  11. }  

来看压缩函数
Java代码   收藏代码
  1. /* 
  2.  * compact操作用于当 
  3.  *  while (in.read(buf) >= 0 || buf.position != 0) { 
  4.  *     buf.flip(); 
  5.  *     out.write(buf); 
  6.  *     buf.compact();    // In case of partial write 
  7.  *    } 
  8.  * 当out发送数据,即读取buf的数据,write方法可能只发送了部分数据,buf里还有剩余, 
  9.  * 这时调用buf.compact()函数将position与limit之间的数据,copy到buf的0到limit-position, 
  10.  * 进行压缩(非实际以压缩,只是移动), 
  11.  * 以便下次 向写入缓存。 
  12.  */  
  13. public ByteBuffer compact() {  
  14.         //将position与limit之间的数据,copy到buf的0到limit-position  
  15.         System.arraycopy(hb, ix(position()), hb, ix(0), remaining());  
  16.     //重新定位position  
  17.         position(remaining());  
  18.     //重新赋值limit  
  19.         limit(capacity());  
  20.     //废弃标记位置  
  21.         discardMark();  
  22.         return this;  
  23.     }  

在来看一下put函数
Java代码   收藏代码
  1. public ByteBuffer putChar(char x) {  
  2.        //Char,占两字节  
  3.        Bits.putChar(this, ix(nextPutIndex(2)), x, bigEndian);  
  4.        return this;  
  5.    }  
  6.   
  7. public ByteBuffer putInt(int x) {  
  8.        //int占4个字节  
  9.        Bits.putInt(this, ix(nextPutIndex(4)), x, bigEndian);  
  10.        return this;  
  11.    }  

我们,详看一下putInt
Java代码   收藏代码
  1. //Buffer  
  2. //判断是否有足够空间存放nb个字节,并返回position的原先位置,同时移动position  
  3.  final int nextPutIndex(int nb) {                    // package-private  
  4.         if (limit - position < nb)  
  5.             throw new BufferOverflowException();  
  6.         int p = position;  
  7.         position += nb;  
  8.         return p;  
  9.     }  

//HeapByteBuffer
Java代码   收藏代码
  1. //定位到缓存写开始的位置  
  2. protected int ix(int i) {  
  3.       return i + offset;  
  4.   }  

//Bits
将int值x,从bb的bi位置,写入
Java代码   收藏代码
  1. static void putInt(ByteBuffer bb, int bi, int x, boolean bigEndian) {  
  2.        if (bigEndian)  
  3.            putIntB(bb, bi, x);  
  4.        else  
  5.            putIntL(bb, bi, x);  
  6.    }  
  7.      
  8.    //由于int占4个字节,将int的每个字节,拆分放入缓存ByteBuffer中  
  9.    static void putIntL(ByteBuffer bb, int bi, int x) {  
  10.        bb._put(bi + 3, int3(x));  
  11.        bb._put(bi + 2, int2(x));  
  12.        bb._put(bi + 1, int1(x));  
  13.        bb._put(bi    , int0(x));  
  14.    }  
  15.    private static byte int3(int x) { return (byte)(x >> 24); }  
  16.    private static byte int2(int x) { return (byte)(x >> 16); }  
  17.    private static byte int1(int x) { return (byte)(x >>  8); }  
  18.    private static byte int0(int x) { return (byte)(x      ); }  

 
从ByteBuffer bb的比位置获取int值
Java代码   收藏代码
  1. static int getIntL(ByteBuffer bb, int bi) {  
  2.         return makeInt(bb._get(bi + 3),  
  3.                        bb._get(bi + 2),  
  4.                        bb._get(bi + 1),  
  5.                        bb._get(bi    ));  
  6.  static private int makeInt(byte b3, byte b2, byte b1, byte b0) {  
  7.         return (((b3       ) << 24) |  
  8.                 ((b2 & 0xff) << 16) |  
  9.                 ((b1 & 0xff) <<  8) |  
  10.                 ((b0 & 0xff)      ));  
  11.     }  

从上面可以看出向缓存中写入占多字节的原始类型Char,int,float等时,
HeapByteBuffer,通过Bit将原始类型字节拆分存入到ByteBuffer的缓存中。


总结:
get*(int index)方法不改变mark,limit和capacity的值;put则回改变position的位置,put操作后position的位置为,put操作之前position+length(put 操作数);
mark操作会改变mark的值,reset操作,则是将position定位到mark;clear操作并不会清空缓冲空间,而是将position复位0,limit为capacity,mark为-1;remain操作返回的是可用的空间大小为capacity-position;如put后,超出缓冲区大小,则抛出BufferOverflowException异常。
compact操作一般在一下情况调用,当out发送数据,即读取buf的数据,write方法可能只发送了部分数据,buf里还有剩余,这时调用buf.compact()函数将position与limit之间的数据,copy到buf的0到limit-position,进行压缩(非实际以压缩,只是移动),以便下次 向写入缓存。当position与limit之间的数据为空时,则不改变原缓冲区,否则copy相应数据。HeapByteBuffer向缓存中写入占多字节的原始类型Char,int,float等时,HeapByteBuffer,通过Bit将原始类型字节拆分存入到ByteBuffer的缓存中。

下面用图来模仿相关操作:
初始化:



写数据:



mark:



再次写数据:



reset操作:





flip操作,左图为操作前,右图为操作后;



rewind操作,左图为操作前,右图为操作后;



clear操作,上图为操作前,下图为操作后;



compact操作,有数据的情况下,上图为操作前,下图为操作后;



compact操作,无数据的情况下,上图为操作前,下图为操作后;






  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值