NIO相比普通IO提供了功能更为强大、处理数据更快的解决方案。常用于高性能服务器上。NIO实现高性能处理的原理是使用较少的线程来处理更多的任务常规io使用的byte[]、char[]进行封装,而NIO采用ByteBuffer类来操作数据,再结合针对File或socket技术的channel,采用同步非阻塞技术来实现高性能处理,而Netty正是采用ByteBuffer(缓冲区)、Channel(通道)、Selector(选择器)进行封装的。因此我们需要先了解NIO相关的知识。
NIO相关知识:首先来了解ByteBuffer和CharBuffer,此时需要了解父类Buffer.
因此需要了解ByteBuffer的底层是否是基于数组实现的?可以看到如果是直接allocate,则不是,而是将元素的信息存入内存中,此时不经过数组,而allocate,则会存入到数组中。同时对于flip翻转有什么作用?我们是否可以自己实现翻转行为?答案是肯定的,同时将上界调为当前位置的大小,通过改变当前位置为0,即可实现,因为翻转的本质是为了实现对数据的获取,将数据进行取出。了解标记mark是什么,了解clear什么,了解hasRemaining()是什么,什么是rewind?什么是偏移量ArrayOffset?缓冲区的标记是一个索引,在调用reset()方法时,会将缓冲区的postion位置重置为该索引。同时mark不是必须的。如果将postion或limit调整为小于该mark值时,该mark会被丢弃,丢弃后mark的值为-1。如果未定义mark,调用reset()方法时会抛出InvalidMarkException异常。clear的作用是还原缓冲区到初始的状态,包含将位置设置为0,将限制设置为容量,并丢弃标记,即一切为默认。从源码中,我们看到,当前位置为0,上界等于容量,同时mark=-1。hasRemaing是判断当前位置到限制之间是否有元素,而remaing则是计算它们之间还有多少个元素。可以看到一开始时,字节数组是没有偏移量的,当时如果将postion设置为大于1的数时,也即当前位置大于0时,此时就会出现偏移量。因为偏移量是相对的。
首先其来自于java.nio下的Buffer:
publicabstractclassBuffer { staticfinalintSPLITERATOR_CHARACTERISTICS=Spliterator.SIZED|Spliterator.SUBSIZED|Spliterator.ORDERED; // 值的关系:mark <= position <= limit <= capacity//也即标记<=位置<=限制<=容量,如果位置、限制<标记,则该标记会被丢弃,//如果未定义mark,则reset时会被抛弃//标记privateintmark=-1; //位置 不能为负数privateintposition=0//限制 不能为负数 privateintlimit; //容量 不能为负数privateintcapacity; //地址,偏移量longaddress; //构造方法:在检查完不变量后创建一个新的带标记、位置、限制、容量的bufferBuffer(intmark, intpos, intlim, intcap) { //检查cap、mark是否<0,if (cap<0) thrownewIllegalArgumentException("Negative capacity: "+cap); this.capacity=cap; limit(lim); position(pos); if (mark>=0) { if (mark>pos) thrownewIllegalArgumentException("mark > position: ("+mark+" > "+pos+")"); this.mark=mark; } } //容量publicfinalintcapacity() { returncapacity; } //当前位置publicfinalintposition() { returnposition; } publicfinalBufferposition(intnewPosition) { if ((newPosition>limit) || (newPosition<0)) thrownewIllegalArgumentException(); position=newPosition; //对mark进行判断,从而是不是-1if (mark>position) mark=-1; returnthis; } publicfinalintlimit() { returnlimit; } publicfinalBufferlimit(intnewLimit) { if ((newLimit>capacity) || (newLimit<0)) thrownewIllegalArgumentException(); limit=newLimit; if (position>limit) position=limit; if (mark>limit) mark=-1; returnthis; } //标记publicfinalBuffermark() { mark=position; returnthis; } publicfinalBufferreset() { intm=mark; if (m<0) thrownewInvalidMarkException(); position=m; returnthis; } //清除,此时当前位置为0,同时清除标记,同时将上界变成了容量publicfinalBufferclear() { position=0; limit=capacity; mark=-1; returnthis; } //翻转publicfinalBufferflip() { limit=position; position=0; mark=-1; returnthis; } //重绕此缓冲区,将位置设置为0并丢弃标记//可以看到将当前位置变成了0publicfinalBufferrewind() { position=0; mark=-1; returnthis; } //返回当前元素与limit之间的元素的数量publicfinalintremaining() { returnlimit-position; } //当前位置是否小于上界,也即还是否有元素publicfinalbooleanhasRemaining() { returnposition<limit; } publicabstractbooleanisReadOnly(); //是否是数组publicabstractbooleanhasArray(); publicabstractObjectarray(); //数组偏移量publicabstractintarrayOffset(); publicabstractbooleanisDirect(); finalintnextGetIndex() { // package-privateif (position>=limit) thrownewBufferUnderflowException(); returnposition++; } finalintnextGetIndex(intnb) { // package-privateif (limit-position<nb) thrownewBufferUnderflowException(); intp=position; position+=nb; returnp; } finalintnextPutIndex() { // package-privateif (position>=limit) thrownewBufferOverflowException(); returnposition++; } finalintnextPutIndex(intnb) { // package-privateif (limit-position<nb) thrownewBufferOverflowException(); intp=position; position+=nb; returnp; } finalintcheckIndex(inti) { // package-privateif ((i<0) || (i>=limit)) thrownewIndexOutOfBoundsException(); returni; } //检查索引finalintcheckIndex(inti, intnb) { // package-privateif ((i<0) || (nb>limit-i)) thrownewIndexOutOfBoundsException(); returni; } finalintmarkValue() { // package-privatereturnmark; } finalvoidtruncate() { // package-privatemark=-1; position=0; limit=0; capacity=0; } finalvoiddiscardMark() { // package-privatemark=-1; } //检查边界:偏移量、长度、大小staticvoidcheckBounds(intoff, intlen, intsize) { // package-privateif ((off|len| (off+len) | (size- (off+len))) <0) thrownewIndexOutOfBoundsException(); } }
从包中,我们可以看到Buffer的子类抽象类包含的信息7个子类,常用的CharBuffer、ByteBuffer:
publicabstractclassByteBufferextendsBufferimplementsComparable<ByteBuffer>publicabstractclassCharBufferextendsBufferimplementsComparable<CharBuffer>, Appendable, CharSequence, ReadablepublicabstractclassDoubleBufferextendsBufferimplementsComparable<DoubleBuffer>publicabstractclassFloatBufferextendsBufferimplementsComparable<FloatBuffer>publicabstractclassIntBufferextendsBufferimplementsComparable<IntBuffer>publicabstractclassLongBufferextendsBufferimplementsComparable<LongBuffer>publicabstractclassShortBufferextendsBufferimplementsComparable<ShortBuffer>
但是我们可以看到其7个子类也是抽象的,不能直接new实例化。那我们如何创建这些类的对象呢?使用的方式将上面7种数据类型的数组包装进缓冲区中,此时需要借助静态方法wrap()进行实现。wrap()方法的作用是将数组放入缓冲区中,来构建存储不同数据类型的缓冲区。比如byteBuffer
publicstaticByteBufferwrap(byte[] array) { //将byte包装成byteBuffer,包装的过程中传入的偏移量为0,同时长度为字节数组的长度returnwrap(array, 0, array.length); } publicstaticByteBufferwrap(byte[] array, intoffset, intlength){ try { returnnewHeapByteBuffer(array, offset, length); } catch (IllegalArgumentExceptionx) { thrownewIndexOutOfBoundsException(); } } //堆字节数组:本质是一个字节数组byte[]HeapByteBuffer(byte[] buf, intoff, intlen) { //从这里我们可以看到标记值为-1super(-1, off, off+len, buf.length, buf, 0); } ByteBuffer(intmark, intpos, intlim, intcap,byte[] hb, intoffset){ super(mark, pos, lim, cap); this.hb=hb; this.offset=offset; } Buffer(intmark, intpos, intlim, intcap) { if (cap<0) thrownewIllegalArgumentException("Negative capacity: "+cap); this.capacity=cap; limit(lim); position(pos); if (mark>=0) { if (mark>pos) thrownewIllegalArgumentException("mark > position: ("+mark+" > "+pos+")"); this.mark=mark; } }
下面我们来了解相关特性:
/*** 进行nio测试:可以看到ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer、ShortBuffer* 是抽象类,而wrap()就相当于创建这些缓冲区的工厂方法,都会经过wrap(array, 0, array.length)方法,比如ByteBuffer会经过* //可以看到hb是一个字节数组* ByteBuffer(int mark, int pos, int lim, int cap,byte[] hb, int offset) {* //调用buffer的构造方法* super(mark, pos, lim, cap);* //仅堆缓冲区为非null* this.hb = hb;* //偏移量* this.offset = offset;* }* <p>* ByteBuffer类缓冲区的技术原理就是使用byte[]数组进行数据保存* 缓冲区存储的数据还是存储在byte[]字节数组中。使用缓冲区与使用byte[]字节数组相比:* 优点在于缓冲区将存储数据的byte[]字节数组内容与相关的信息整合在1个Buffer类中,将* 数据与缓冲区中的信息进行了整合,并进行了封装,这样便于得到相关的信息和处理数据*/publicclassNIOTest { publicstaticvoidmain(String[] args) { byte[] byteArray=newbyte[]{1, 2, 3}; short[] shortArray=newshort[]{1, 2, 3, 4}; int[] intArray=newint[]{1, 2, 3, 4, 5}; long[] longArray=newlong[]{1, 2, 3, 4, 5, 6, 7}; float[] floatArray=newfloat[]{1, 2, 3, 4, 5, 6, 7}; double[] doubleArray=newdouble[]{1, 2, 3, 4, 5, 6, 7, 8}; char[] charArray=newchar[]{'a', 'b', 'c', 'd'}; ByteBufferbyteBuffer=ByteBuffer.wrap(byteArray); ShortBuffershortBuffer=ShortBuffer.wrap(shortArray); IntBufferintBuffer=IntBuffer.wrap(intArray); LongBufferlongBuffer=LongBuffer.wrap(longArray); FloatBufferfloatBuffer=FloatBuffer.wrap(floatArray); DoubleBufferdoubleBuffer=DoubleBuffer.wrap(doubleArray); CharBuffercharBuffer=CharBuffer.wrap(charArray); /*** 返回结果:* 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*/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("byteBufffer.capacity="+byteBuffer.capacity()); System.out.println("shortBuffer.capacity="+shortBuffer.capacity()); System.out.println("intBuffer.capacity="+intBuffer.capacity()); System.out.println("longBuffer.capacity="+longBuffer.capacity()); System.out.println("floatBuffer.capacity="+floatBuffer.capacity()); System.out.println("doubleBuffer.capacity="+doubleBuffer.capacity()); System.out.println("charBuffer.capacity="+charBuffer.capacity()); } }
运行结果:
byteBuffer=java.nio.HeapByteBuffershortBuffer=java.nio.HeapShortBufferintBuffer=java.nio.HeapIntBufferlongBuffer=java.nio.HeapLongBufferfloatBuffer=java.nio.HeapFloatBufferdoubleBuffer=java.nio.HeapDoubleBuffercharBuffer=java.nio.HeapCharBuffer======================================byteBufffer.capacity=3shortBuffer.capacity=4intBuffer.capacity=5longBuffer.capacity=7floatBuffer.capacity=7doubleBuffer.capacity=8charBuffer.capacity=4
可以看到它会调用包装方法,进行包装也即上面所看到的wrap方法。最终是一个和堆有关的buffer的字节数组。
/*** 进行limit和position使用*/publicclassNIOTest2 { publicstaticvoidmain(String[] args) { char[] charArray=newchar[]{'a', 'b', 'c', 'd', 'd', 'e', 'f', 'g'}; CharBufferbuffer=CharBuffer.wrap(charArray); System.out.println("A capacity()="+buffer.capacity() +" limit()="+buffer.limit()); buffer.limit(4); //buffer.position(2);System.out.println("B capacity()="+buffer.capacity() +" limit()="+buffer.limit()); buffer.put(0, '0'); buffer.put(1, 'h'); buffer.put(2, '3'); buffer.put(3, 'i'); //会在这里抛异常,因为指定了现在4个数据buffer.put(4, 'j'); buffer.put(5, 'k'); } }
运行结果:
Exceptioninthread"main"java.lang.IndexOutOfBoundsExceptionatjava.nio.Buffer.checkIndex(Buffer.java:540) atjava.nio.HeapCharBuffer.put(HeapCharBuffer.java:178) atcom.study.nio.NIOTest2.main(NIOTest2.java:21) Acapacity()=8limit()=8Bcapacity()=8limit()=4
从运行的结果中,我们可以看到原来包装的buffer的容量是8,同时上界是8。而设置上界为4,此时当添加数据到第四个位置时,会抛异常。
/*** 进行limit和position、remaining的使用*/publicclassNIOTest3 { publicstaticvoidmain(String[] args) { char[] charArray=newchar[]{'a', 'b', 'c', 'd', 'd', 'e', 'f', 'g'}; CharBufferbuffer=CharBuffer.wrap(charArray); System.out.println("A capacity()="+buffer.capacity() +" limit()="+buffer.limit() +" position()="+buffer.position()); buffer.limit(5); //buffer的下一个位置是2号角标的位置buffer.position(2); //remaining()的作用:返回当前位置与limit之间的元素数,也即:remaining=limit-postionSystem.out.println("remaining()="+buffer.remaining()); System.out.println("B capacity()="+buffer.capacity() +" limit()="+buffer.limit() +" position()="+buffer.position()); buffer.put('i'); //第三个数据c会变成ifor (inti=0; i<charArray.length; i++) { System.out.println(charArray[i] +" "); } } }
运行结果:
Acapacity()=8limit()=8position()=0remaining()=3Bcapacity()=8limit()=5position()=2abiddefg
/*** 使用buffer mark()方法处理标记* mark()的作用:在此缓冲区的位置设置标记,* 缓冲去的标记是一个索引,在调用reset()方法时,* 会将缓冲区的position位置重置为索引位置。* <p>* 如果定义了mark,则在将postion或limit调整为小于该mark的值时,该mark会被丢弃,丢弃后mark的值为-1* 如果未定义mark,调用reset会抛出InvalidMarkException异常* 同时可以看到默认是不开启直接缓冲区的,需要手动设置,此时在jvm和硬盘之间可以少了一个中间缓冲区,提高程序运行的效率*/publicclassNIOTest4 { publicstaticvoidmain(String[] args) { byte[] byteArray=newbyte[]{'a', 'b', 'c', 'd', 'd', 'e', 'f'}; ByteBufferbuffer=ByteBuffer.wrap(byteArray); System.out.println("A capacity()="+buffer.capacity() +" limit()="+buffer.limit() +" position()="+buffer.position()); buffer.limit(5); //buffer的下一个位置是2号角标的位置buffer.position(2); //在位置2设置markbuffer.mark(); System.out.println("remaining()="+buffer.remaining()); System.out.println("B capacity()="+buffer.capacity() +" limit()="+buffer.limit() +" position()="+buffer.position()); buffer.position(3); //位置重置,postion的位置会回到mark的位置buffer.reset(); //remaining()的作用:返回当前位置与limit之间的元素数,也即:remaining=limit-postionSystem.out.println("remaining()="+buffer.remaining()); System.out.println("B capacity()="+buffer.capacity() +" limit()="+buffer.limit() +" position()="+buffer.position()); //可以看到不是直接缓冲区System.out.println(buffer.isDirect()); ByteBufferbyBuffer=ByteBuffer.allocate(100); System.out.println("默认关闭,此时调用的不是直接缓冲区:"+byBuffer.isDirect()); ByteBufferbyteBuffer=ByteBuffer.allocateDirect(100); System.out.println("此时调用的是直接缓冲区:"+byteBuffer.isDirect()); } }
运行结果:
Acapacity()=7limit()=7position()=0remaining()=3Bcapacity()=7limit()=5position()=2remaining()=3Bcapacity()=7limit()=5position()=2false默认关闭,此时调用的不是直接缓冲区:false此时调用的是直接缓冲区:true
可以看到如果当前位置为2,上界为5时,如果设置为mark,则此时剩下的元素是3。同时可以看到如果是直接缓冲区,则调用的是内存,否则不是直接缓冲区。
/*** 对缓存区进行反转 flip()方法:原理是首先将闲置设置为当前位置,然后将* 位置设置为0.如果定义了标记,则丢弃该标记。* public Buffer flip(){* limit = postion;* postion = 0;* mark = -1;* return this;* }*/publicclassNIOTest5 { publicstaticvoidmain(String[] args) { byte[] byteArray=newbyte[]{'a', 'b', 'c', 'd', 'd', 'e'}; ByteBufferbuffer=ByteBuffer.wrap(byteArray); System.out.println("A capacity()="+buffer.capacity() +" limit()="+buffer.limit() +" position()="+buffer.position()); //buffer的下一个位置是2号角标的位置buffer.position(2); //在位置2设置markbuffer.mark(); buffer.flip(); System.out.println("remaining()="+buffer.remaining()); System.out.println("B capacity()="+buffer.capacity() +" limit()="+buffer.limit() +" position()="+buffer.position()); //位置重置,postion的位置会回到mark的位置try { buffer.reset(); } catch (Exceptione) { System.out.println("buffer的mark丢失了。。。"); } //remaining()的作用:返回当前位置与limit之间的元素数,也即:remaining=limit-postionSystem.out.println("remaining()="+buffer.remaining()); System.out.println("B capacity()="+buffer.capacity() +" limit()="+buffer.limit() +" position()="+buffer.position()); } }
运行结果:
Acapacity()=6limit()=6position()=0remaining()=2Bcapacity()=6limit()=2position()=0buffer的mark丢失了。。。remaining()=2Bcapacity()=6limit()=2position()=0
flip操作会将原来的位置翻转到初始位置。从源码中可以看到其会将postion设置为0。
/*** 测试postion和limit的使用,模仿flip行为*/publicclassNIOTest6 { publicstaticvoidmain(String[] args) { //创建一个CharBuffer,容量为20CharBuffercharBuffer=CharBuffer.allocate(20); //查看当前位置和限制大小,你可以理解为上界System.out.println("A postion = "+charBuffer.position() +"limit="+charBuffer.limit()); //写入字符charBuffer.put("一个前行在路上的行路人"); System.out.println("B postion ="+charBuffer.position() +"limit="+charBuffer.limit()); //还原位置到0charBuffer.position(0); System.out.println("C postion = "+charBuffer.position() +"limit="+charBuffer.limit()); //写入字符charBuffer.put("学无止境,你在前行"); System.out.println("D postion = "+charBuffer.position() +"limit="+charBuffer.limit()); //还原缓冲区的状态charBuffer.clear(); System.out.println("E postion = "+charBuffer.position() +"limit="+charBuffer.limit()); //继续写入charBuffer.put("我不前行的时候,你也在前行"); charBuffer.append("我要更努力"); charBuffer.limit(charBuffer.position()); charBuffer.position(0); for (inti=0; i<charBuffer.limit(); i++) { System.out.print(charBuffer.get()); } System.out.println(" "); } }
运行结果:
Apostion=0limit=20Bpostion=11limit=20Cpostion=0limit=20Dpostion=9limit=20Epostion=0limit=20我不前行的时候,你也在前行我要更努力
从上面的运行结果看,我们成功模仿了flip的翻转行为。
/*** 使用flip解决NIOTest6的行为*/publicclassNIOTest7 { publicstaticvoidmain(String[] args) { //创建一个CharBuffer,容量为20CharBuffercharBuffer=CharBuffer.allocate(20); //查看当前位置和限制大小,你可以理解为上界System.out.println("A postion = "+charBuffer.position() +"limit="+charBuffer.limit()); //写入字符charBuffer.put("一个前行在路上的行路人"); System.out.println("B postion ="+charBuffer.position() +"limit="+charBuffer.limit()); //还原位置到0charBuffer.position(0); System.out.println("C postion = "+charBuffer.position() +"limit="+charBuffer.limit()); //写入字符charBuffer.put("学无止境,你在前行"); System.out.println("D postion = "+charBuffer.position() +"limit="+charBuffer.limit()); //还原缓冲区的状态charBuffer.clear(); System.out.println("E postion = "+charBuffer.position() +"limit="+charBuffer.limit()); //继续写入charBuffer.put("我不前行的时候,你也在前行"); charBuffer.append("我要更努力"); //charBuffer.limit(charBuffer.position());//charBuffer.position(0);charBuffer.flip(); for (inti=0; i<charBuffer.limit(); i++) { System.out.print(charBuffer.get()); } System.out.println(" "); } }
也即:
charBuffer.limit(charBuffer.position()); charBuffer.position(0); =>charBuffer.flip();
/*** 查看缓冲区底层实现是否是数组实现的*/publicclassNIOTest8 { publicstaticvoidmain(String[] args) { allocateDemo(); allocateDirectDemo(); } privatestaticvoidallocateDemo() { ByteBufferbyteBuffer=ByteBuffer.allocate(100); byteBuffer.put((byte) 1); byteBuffer.put((byte) 2); //返回true,说明底层是数组实现的,说明数据存储在数组中System.out.println("缓冲区的底层基于数组实现:"+byteBuffer.hasArray()); } privatestaticvoidallocateDirectDemo() { ByteBufferbyteBuffer=ByteBuffer.allocateDirect(100); byteBuffer.put((byte) 1); byteBuffer.put((byte) 2); //返回true,说明底层是数组实现的,而返回false,说明数据并没有直接存储在数组中,而是直接存储在内存中System.out.println("直接缓冲区的底层基于数组实现:"+byteBuffer.hasArray()); } }
运行结果:
缓冲区的底层基于数组实现:true直接缓冲区的底层基于数组实现:false
/*** 判断当前位置和限制之间是否有剩余元素* 进行迭代*/publicclassNIOTest9 { publicstaticvoidmain(String[] args) { hasRemain(); hasElementGet(); } //测试还剩下的元素privatestaticvoidhasRemain() { byte[] byteArray=newbyte[]{1, 2, 3, 4}; ByteBufferbyteBuffer=ByteBuffer.wrap(byteArray); byteBuffer.limit(4); byteBuffer.position(2); System.out.println("byteBuffer.hasRemaining="+byteBuffer.hasRemaining() +" "+"byteBuffer.remaining="+byteBuffer.remaining()); } //使用剩下的特性,进行迭代privatestaticvoidhasElementGet() { byte[] byteArray=newbyte[]{1, 2, 3, 4, 5}; ByteBufferbyteBuffer=ByteBuffer.wrap(byteArray); intremaining=byteBuffer.remaining(); for (inti=0; i<remaining; i++) { System.out.print(byteBuffer.get() +""); } System.out.println(""); byteBuffer.clear(); while (byteBuffer.hasRemaining()) { System.out.print(byteBuffer.get() +""); } System.out.println(""); byteBuffer.clear(); for (; byteBuffer.hasRemaining() ==true; ) { System.out.print(byteBuffer.get() +""); } System.out.println(""); } }
运行结果:
byteBuffer.hasRemaining=truebyteBuffer.remaining=2123451234512345
/*** 对于flip、clear、rewind之间的区别:* remind:标记清除,位置postion值归0,limit不变* public final Buffer rewind(){* postion = 0;* mark = -1;* return this;* }* <p>* clear:清除缓冲区,将位置设置为0,将限制设置为容量,并丢弃标记* public final Buffer clear(){* postion = 0;* limit = capacity;* mark = -1;* return -1;* }* <p>* flip:反转缓冲区,首先将限制设置为当前位置,然后将位置设置为0.* public final Buffer flip(){* limit = postion;* postion = 0;* mark = -1;* return this;* }* <p>* 三者的侧重点:* rewind:侧重在重新,在重新读取、重新写入时使用* clear:侧重还原一切状态* flip:侧重在substring截取*/publicclassNIOTest10 { publicstaticvoidmain(String[] args) { byte[] byteArray=newbyte[]{1, 2, 3, 4}; ByteBufferbyteBuffer=ByteBuffer.wrap(byteArray); System.out.println("capacity="+byteBuffer.capacity() +" "+"limit="+byteBuffer.limit() +" "+"postion="+byteBuffer.position()); byteBuffer.position(1); byteBuffer.limit(3); byteBuffer.mark(); System.out.println("capacity="+byteBuffer.capacity() +" "+"limit="+byteBuffer.limit() +" "+"postion="+byteBuffer.position()); byteBuffer.rewind(); System.out.println("capacity="+byteBuffer.capacity() +" "+"limit="+byteBuffer.limit() +" "+"postion="+byteBuffer.position()); } }
运行结果:
capacity=4limit=4postion=0capacity=4limit=3postion=1capacity=4limit=3postion=0
/*** 获取偏移量 ArrayOffset* final int arrayOffset():返回此缓冲区的底层实现数组中的第一个缓冲区元素的偏移量* public final int arrayOffset(){* if(hb==null)* throw new UnsupportedOperationException();* if(isReadOnly)* throw new ReadOnlyBufferException();* return offset;* }*/publicclassNIOTest11 { publicstaticvoidmain(String[] args) { getArrayOffsetZero(); getArrayOffset(); } //测试结果永远都为0的情况privatestaticvoidgetArrayOffsetZero() { byte[] byteArray=newbyte[]{1,2,3,4,5,6}; ByteBufferbyteBuffer=ByteBuffer.wrap(byteArray); System.out.println("byteBuffer.arrayOffset ="+byteBuffer.arrayOffset()); } //测试不为0的情况,偏移是相对而言的privatestaticvoidgetArrayOffset() { byte[] byteArray=newbyte[]{1,2,3,4,5,6}; ByteBufferbyteBuffer=ByteBuffer.wrap(byteArray); byteBuffer.position(5); ByteBufferbyteBuffer1=byteBuffer.slice(); System.out.println("byteBuffer.arrayOffset ="+byteBuffer1.arrayOffset()); } }
运行结果:
byteBuffer.arrayOffset=0byteBuffer.arrayOffset=5
/*** 使用List.toArray(T[])*/publicclassNIOTest12 { publicstaticvoidmain(String[] args) { ByteBufferbuffer1=ByteBuffer.wrap(newbyte[]{'1','2','3','4'}); ByteBufferbuffer2=ByteBuffer.wrap(newbyte[]{'c','d','t','v'}); ByteBufferbuffer3=ByteBuffer.wrap(newbyte[]{'x','m','a','n'}); List<ByteBuffer>list=newArrayList<>(); list.add(buffer1); list.add(buffer2); list.add(buffer3); ByteBuffer[] byteBufferArray=newByteBuffer[list.size()]; list.toArray(byteBufferArray); System.out.println(byteBufferArray.length); for (inti=0; i<byteBufferArray.length;i++){ ByteBuffereachByteBuffer=byteBufferArray[i]; while (eachByteBuffer.hasRemaining()){ System.out.print((char)eachByteBuffer.get()); } System.out.println(); } } }
运行结果:
31234cdtvxman
/*** 进行测试,包装wrap数据的处理*/publicclassNIOTest13 { publicstaticvoidmain(String[] args) { byte[] byteArray=newbyte[]{1, 2, 3, 4, 5, 56}; ByteBufferbyteBuffer=ByteBuffer.wrap(byteArray); ByteBufferbyteBuffer1=ByteBuffer.wrap(byteArray, 2, 4); System.out.println("byteBuffer capacity="+byteBuffer.capacity() +" "+"postion="+byteBuffer.position()); System.out.println(); System.out.println("byteBuffer1 capacity="+byteBuffer1.capacity() +" "+"postion="+byteBuffer1.position()); } }
运行结果:
byteBuffercapacity=6postion=0byteBuffer1capacity=6postion=2
了解完Buffer之后,我们就可以接着了解ByteBuffer和CharBuffer了。