博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
深入研究Netty框架之ByteBuf功能原理及源码分析
阅读量:6995 次
发布时间:2019-06-27

本文共 18486 字,大约阅读时间需要 61 分钟。

hot3.png

ByteBuf功能原理

ByteBuf是一个byte数组的缓冲区,通过两个位置指针完成缓冲区的读写操作,读操作使用readerIndex,写操作使用writeIndex。

readerIndex和writeIndex初始取值均为0,写入数据,writeIndex增加;读取数据则readerIndex增加。0~readerIndex之间的数据是已经读取的,调用discardReadBytes()可释放这部分空间,其作用类似于JDK ByteBuffer的compact()方法;readerIndex~writeIndex之间的数据是可读取的,等价于ByteBuffer position和limit之间的数据;writeIndex和capacity之间的空间是可写入的,等价于ByteBuffer limit和capacity之间的可用空间;调用clear()可重置readerIndex和writeIndex为0,但该操作不会清理buffer中的内容。

初始分配的ByteBuf:

+-------------------------------------------------------+|                writable bytes                         |+-------------------------------------------------------+|                                                       |0 = readerIndex = writerIndex                       capacity

写入N个字节后的ByteBuf:

+-------------------------------------+------------------+|       readable bytes                |  writable bytes  ||       (CONTENT)                     |                  |+-------------------------------------+------------------+|                                     |                  |0 = readerIndex                N = writerIndex    <=  capacity

读取M(<=N)个字节后的ByteBuf:

+-------------------+------------------+------------------+| discardable bytes |  readable bytes  |  writable bytes  ||                   |     (CONTENT)    |                  |+-------------------+------------------+------------------+|                   |                  |                  |0          M  = readerIndex  <=    N = writerIndex  <= capacity

调用discardReadBytes()方法之后的ByteBuf:

+-------------------+---------------------+|   readable bytes  |  writable bytes     |+-------------------+---------------------+|                   |                     |0 = readerIndex   N-M = writerIndex  <= capacity

调用clear()方法之后的ByteBuf:

+-------------------------------------------------------+|                writable bytes                         |+-------------------------------------------------------+|                                                       |0 = readerIndex = writerIndex                       capacity

ByteBuf 动态扩展

通常情况下,当对JDK ByteBuffer进行put操作时,如果缓冲区可写空间不够,就会抛出BufferOverflowException异常。为了避免这个问题,在进行put操作时,需要对可写空间进行判断,如果剩余可写空间不足,需要创建一个新ByteBuffer,并将之前ByteBuffer的内容复制到新创建的ByteBuffer中,然后释放老的ByteBuffer。

//needSize为需要写入的字节数if(this.buffer.remaining()
128 ? needSize:128; ByteBuffer newBuffer=ByteBuffer.allocate(this.buffer.capacity()+realAllocateSize); this.buffer.flip(); newBuffer.put(this.buffer); this.buffer=newBuffer;}

为防止ByteBuffer溢出,每次进行put操作都需要进行可写空间校验,这导致了代冗余。

为了解决这个问题,ByteBuf对write方法进行了封装,由write操作负责进行剩余可用空间的校验,当空间不足时,由ByteBuf自动进行动态扩展(不超过maxCapacity),使用者无需关心底层的校验和动态扩展细节。

源码如下:

@Override    public ByteBuf writeBytes(ByteBuf src, int srcIndex, int length) {        ensureWritable(length);        setBytes(writerIndex, src, srcIndex, length);        writerIndex += length;        return this;    }

当执行writeBytes时,先调用ensureWritable(length)进行可写空间的校验。

@Override    public ByteBuf ensureWritable(int minWritableBytes) {        if (minWritableBytes < 0) {            throw new IllegalArgumentException(String.format(                    "minWritableBytes: %d (expected: >= 0)", minWritableBytes));        }        if (minWritableBytes <= writableBytes()) {            return this;        }        if (minWritableBytes > maxCapacity - writerIndex) {            throw new IndexOutOfBoundsException(String.format(                    "writerIndex(%d) + minWritableBytes(%d) exceeds maxCapacity(%d): %s",                    writerIndex, minWritableBytes, maxCapacity, this));        }        // Normalize the current capacity to the power of 2.        int newCapacity = calculateNewCapacity(writerIndex + minWritableBytes);        // Adjust to the new capacity.        capacity(newCapacity);        return this;    }

当需要写入的字节数大于缓冲区最大可写字节数时,ByteBuf自动进行动态扩展。calculateNewCapacity(writerIndex + minWritableBytes)方法用于计算缓冲区新的容量,capacity(newCapacity)则用于实现动态扩展,后面会详细介绍其源码。

ByteBuf 主要API

顺序读操作(read)

方法名称 返回值 功能说明 抛出异常
readBoolean() boolean

从readerIndex开始读取1字节的数据

throws IndexOutOfBoundsException

readableBytes<1

readByte() byte 从readerIndex开始读取1字节的数据

throws IndexOutOfBoundsException

readableBytes<1

readUnsignedByte() short 从readerIndex开始读取1字节的数据(无符号字节值)

throws IndexOutOfBoundsException:

readableBytes<1

readShort() short 从readerIndex开始读取16位的短整形值

throws IndexOutOfBoundsException:

readableBytes<2

readUnsignedShort() int 从readerIndex开始读取16位的无符号短整形值

throws IndexOutOfBoundsException:

readableBytes<2

readMedium() int 从readerIndex开始读取24位的整形值,(该类型并非java基本类型,通常不用)

throws IndexOutOfBoundsException:

readableBytes<3

readUnsignedMedium() int 从readerIndex开始读取24位的无符号整形值,(该类型并非java基本类型,通常不用)

throws IndexOutOfBoundsException:

readableBytes<3

readInt() int 从readerIndex开始读取32位的整形值

throws IndexOutOfBoundsException:

readableBytes<4

readUnsignedInt() long 从readerIndex开始读取32位的无符号整形值

throws IndexOutOfBoundsException:

readableBytes<4

readLong() long 从readerIndex开始读取64位的整形值

throws IndexOutOfBoundsException:

readableBytes<8

readChar() char 从readerIndex开始读取2字节的字符值

throws IndexOutOfBoundsException:

readableBytes<2

readFloat() float 从readerIndex开始读取32位的浮点值

throws IndexOutOfBoundsException:

readableBytes<4

readDouble() double 从readerIndex开始读取64位的浮点值

throws IndexOutOfBoundsException:

readableBytes<8

readBytes(int length) ByteBuf

将当前ByteBuf中的数据读取到新创建的ByteBuf中,从readerIndex开始读取length字节的数据。返回的ByteBuf readerIndex 为0,writeIndex为length。

throws IndexOutOfBoundsException:

readableBytes<length

readSlice(int length) ByteBuf 返回当前ByteBuf新创建的子区域,子区域和原ByteBuf共享缓冲区的内容,但独立维护自己的readerIndex和writeIndex,新创建的子区域readerIndex 为0,writeIndex为length。

throws IndexOutOfBoundsException:

readableBytes<length

readBytes(ByteBuf dst) ByteBuf

将当前ByteBuf中的数据读取到目标ByteBuf (dst)中,从当前ByteBuf readerIndex开始读取,直到目标ByteBuf无可写空间,从目标ByteBuf writeIndex开始写入数据。读取完成后,当前ByteBuf的readerIndex+=读取的字节数。目标ByteBuf的writeIndex+=读取的字节数。

throws IndexOutOfBoundsException:

this.readableBytes<dst.writableBytes

readBytes(ByteBuf dst, int length) ByteBuf 将当前ByteBuf中的数据读取到目标ByteBuf (dst)中,从当前ByteBuf readerIndex开始读取,长度为length,从目标ByteBuf writeIndex开始写入数据。读取完成后,当前ByteBuf的readerIndex+=length,目标ByteBuf的writeIndex+=length

throws IndexOutOfBoundsException:

this.readableBytes<length or

dst.writableBytes<length

readBytes(ByteBuf dst, int dstIndex, int length) ByteBuf 将当前ByteBuf中的数据读取到目标ByteBuf (dst)中,从readerIndex开始读取,长度为length,从目标ByteBuf dstIndex开始写入数据。读取完成后,当前ByteBuf的readerIndex+=length,目标ByteBuf的writeIndex+=length

throws IndexOutOfBoundsException:

dstIndex<0 or

this.readableBytes<length or

dst.capacity<dstIndex + length

readBytes(byte[] dst) ByteBuf 将当前ByteBuf中的数据读取到byte数组dst中,从当前ByteBuf readerIndex开始读取,读取长度为dst.length,从byte数组dst索引0处开始写入数据。

throws IndexOutOfBoundsException:

this.readableBytes<dst.length

readBytes(byte[] dst, int dstIndex, int length) ByteBuf 将当前ByteBuf中的数据读取到byte数组dst中,从当前ByteBuf readerIndex开始读取,读取长度为length,从byte数组dst索引dstIndex处开始写入数据。

throws IndexOutOfBoundsException:

dstIndex<0 or 

this.readableBytes<length or 

dst.length<dstIndex + length

readBytes(ByteBuffer dst) ByteBuf 将当前ByteBuf中的数据读取到ByteBuffer dst中,从当前ByteBuf readerIndex开始读取,直到dst的位置指针到达ByteBuffer 的limit。读取完成后,当前ByteBuf的readerIndex+=dst.remaining()

throws IndexOutOfBoundsException:

this.readableBytes<dst.remaining() 

readBytes(OutputStream out, int length) ByteBuf 将当前ByteBuf readerIndex读取数据到输出流OutputStream中,读取的字节长度为length

throws IndexOutOfBoundsException:

this.readableBytes<length 

throws  IOException

readBytes(GatheringByteChannel out, int length)  int 将当前ByteBuf readerIndex读取数到GatheringByteChannel 中,写入out的最大字节长度为length。GatheringByteChannel为非阻塞Channel,调用其write方法不能够保存将全部需要写入的数据均写入成功,存在半包问题。因此其写入的数据长度为【0,length】,如果操作成功,readerIndex+=实际写入的字节数,返回实际写入的字节数

throws IndexOutOfBoundsException:

this.readableBytes<length 

throws  IOException

顺序写操作(write)

方法名称 返回值 功能说明 抛出异常
writeBoolean(boolean value) ByteBuf

将value写入到当前ByteBuf中。写入成功,writeIndex+=1

throws IndexOutOfBoundsException:

this.writableBytes<1

writeByte(int value) ByteBuf 将value写入到当前ByteBuf中。写入成功,writeIndex+=1

throws IndexOutOfBoundsException:

this.writableBytes<1

writeShort(int value) ByteBuf 将value写入到当前ByteBuf中。写入成功,writeIndex+=2

throws IndexOutOfBoundsException:

this.writableBytes<2

writeMedium(int   value) ByteBuf 将value写入到当前ByteBuf中。写入成功,writeIndex+=3

throws IndexOutOfBoundsException:

this.writableBytes<3

writeInt(int   value) ByteBuf 将value写入到当前ByteBuf中。写入成功,writeIndex+=4

throws IndexOutOfBoundsException:

this.writableBytes<4

writeLong(long  value) ByteBuf 将value写入到当前ByteBuf中。写入成功,writeIndex+=8

throws IndexOutOfBoundsException:

this.writableBytes<8

writeChar(int value) ByteBuf 将value写入到当前ByteBuf中。写入成功,writeIndex+=2

throws IndexOutOfBoundsException:

this.writableBytes<2

writeFloat(float value) ByteBuf 将value写入到当前ByteBuf中。写入成功,writeIndex+=4

throws IndexOutOfBoundsException:

this.writableBytes<4

writeDouble(double value) ByteBuf 将value写入到当前ByteBuf中。写入成功,writeIndex+=8

throws IndexOutOfBoundsException:

this.writableBytes<8

writeBytes(ByteBuf src) ByteBuf 将源ByteBuf src中从readerIndex开始的所有可读字节写入到当前ByteBuf。从当前ByteBuf writeIndex写入数据。写入成功,writeIndex+=src.readableBytes

throws IndexOutOfBoundsException:

this.writableBytes<src.readableBytes

writeBytes(ByteBuf src, int length) ByteBuf 将源ByteBuf src中从readerIndex开始,长度length的可读字节写入到当前ByteBuf。从当前ByteBuf writeIndex写入数据。写入成功,writeIndex+=length

throws IndexOutOfBoundsException:

this.writableBytes<length or

src.readableBytes<length

writeBytes(ByteBuf src, int srcIndex, int length) ByteBuf 将源ByteBuf src中从srcIndex开始,长度length的可读字节写入到当前ByteBuf。从当前ByteBuf writeIndex写入数据。写入成功,writeIndex+=length

throws IndexOutOfBoundsException:

srcIndex<0  or

this.writableBytes<length or

src.capacity<srcIndex + length

writeBytes(byte[] src) ByteBuf 将源字节数组src中所有可读字节写入到当前ByteBuf。从当前ByteBuf writeIndex写入数据。写入成功,writeIndex+=src.length

throws IndexOutOfBoundsException:

this.writableBytes<src.length

writeBytes(byte[] src, int srcIndex, int length) ByteBuf 将源字节数组src中srcIndex开始,长度为length可读字节写入到当前ByteBuf。从当前ByteBuf writeIndex写入数据。写入成功,writeIndex+=length

throws IndexOutOfBoundsException:

srcIndex<0 or

this.writableBytes<src.length or

src.length<srcIndex + length

writeBytes(ByteBuffer mignsrc) ByteBuf 将源ByteBuffer src中所有可读字节写入到当前ByteBuf。从当前ByteBuf writeIndex写入数据。写入成功,writeIndex+=src.remaining()

throws IndexOutOfBoundsException:

this.writableBytes<src.remaining()

writeBytes(InputStream in, int length) int 将源InputStream in中的内容写入到当前ByteBuf,写入的最大长度为length,实际写入的字节数可能少于length。从当前ByteBuf writeIndex写入数据。写入成功,writeIndex+=实际写入的字节数。返回实际写入的字节数

throws IndexOutOfBoundsException:

this.writableBytes<length

writeBytes(ScatteringByteChannel in, int length) int 将源ScatteringByteChannel in中的内容写入到当前ByteBuf,写入的最大长度为length,实际写入的字节数可能少于length。从当前ByteBuf writeIndex写入数据。写入成功,writeIndex+=实际写入的字节数。返回实际写入的字节数

throws IndexOutOfBoundsException:

this.writableBytes<length

writeZero(int length) ByteBuf 将当前缓冲区的内容填充为NUL(0x00),当前ByteBuf writeIndex写入数据。写入成功,writeIndex+=length

throws IndexOutOfBoundsException:

this.writableBytes<length

readerIndex 和 writeIndex

调用ByteBuf的read操作时,从readerIndex开始读取数据,调用ByteBuf的write操作时,从writeIndex开始写入数据,readerIndex和writeInde关系如下:

+-------------------+------------------+------------------+| discardable bytes |  readable bytes  |  writable bytes  ||                   |     (CONTENT)    |                  |+-------------------+------------------+------------------+|                   |                  |                  |0      <=      readerIndex   <=   writerIndex    <=    capacity
方法名称 返回值 功能说明 抛出异常
readerIndex() int 返回当前ByteBuf的readerIndex  
readerIndex(int readerIndex) ByteBuf 修改当前ByteBuf的readerIndex

throws IndexOutOfBoundsException

this.writerIndex<readerIndex

writerIndex() int 返回当前ByteBuf的writeIndex  
writerIndex(int writerIndex) ByteBuf 修改当前ByteBuf的writeIndex

throws IndexOutOfBoundsException

writeIndex<this.readerIndex or

this.capacity<writerIndex

readableBytes() int

获取当前ByteBuf的可读字节数

this.writerIndex -this.readerIndex

 
writableBytes() int

获取当前ByteBuf的可写字节数

this.capacity - this.writerIndex

 
setIndex(int readerIndex, int writerIndex) ByteBuf 快捷设置当前ByteBuf的readerIndex和writerIndex

throws IndexOutOfBoundsException

readerIndex<0 or

this.writerIndex<readerIndex or

this.capacity<writerIndex

skipBytes(int length) ByteBuf 更新当前ByteBuf的readerIndex,更新后将跳过length字节的数据读取。

throws IndexOutOfBoundsException

this.readableBytes<length

释放空间和clear操作

方法名称 返回值 功能说明
 discardReadBytes() ByteBuf 释放0到readerIndex之间已经读取的空间;同时复制readerIndex和writerIndex之间的数据到0到writerIndex-readerIndex之间;修改readerIndex和writerIndex的值。该操作会发生字节数据的内存复制,频繁调用会导致性能下降。此外,相比其他java对象,缓冲区的分配和释放是个耗时的操作,缓冲区的动态扩张需要进行进行字节数据的复制,也是耗时的操作,因此应尽量提高缓冲区的重用率
discardSomeReadBytes() ByteBuf 功能和discardReadBytes()相似,不同之处在于可定制要释放的空间,依赖于具体实现
clear() ByteBuf 与JDK 的ByteBuffer clear操作相同,该操作不会清空缓冲区内容本身,其主要是为了操作位置指针,将readerIndex和writerIndex重置为0

mark和rest

当对缓冲区进行读写操作时,可能需要对之前的操作进行回滚。ByteBuf可通过调用mark操作将当前的位置指针备份到mark变量中,调用rest操作后,重新将指针的当前位置恢复为备份在mark变量的值。ByteBuf主要有以下相关方法:

markReaderIndex():将当前的readerIndex备份到markedReaderIndex中;

resetReaderIndex():将当前的readerIndex重置为markedReaderIndex的值;

markWriterIndex() :将当前的writerIndex备份到markedWriterIndex中;

resetWriterIndex():将当前的writerIndex重置为markedWriterIndex的值;

相关源码:

@Override    public ByteBuf markReaderIndex() {        markedReaderIndex = readerIndex;        return this;    }    @Override    public ByteBuf resetReaderIndex() {        readerIndex(markedReaderIndex);        return this;    }    @Override    public ByteBuf markWriterIndex() {        markedWriterIndex = writerIndex;        return this;    }    @Override    public ByteBuf resetWriterIndex() {        writerIndex = markedWriterIndex;        return this;    }

查找操作

方法名称 返回值 功能说明 抛出异常
indexOf(int fromIndex, int toIndex, byte value) int 从当前ByteBuf中查找首次出现value的位置,fromIndex<=查找范围<toIndex;查找成功返回位置索引,否则返回-1  
bytesBefore(byte value) int 从当前ByteBuf中查找首次出现value的位置,readerIndex<=查找范围<writerIndex;查找成功返回位置索引,否则返回-1  
bytesBefore(int length, byte value) int 从当前ByteBuf中查找首次出现value的位置,readerIndex<=查找范围<readerIndex+length;查找成功返回位置索引,否则返回-1

IndexOutOfBoundsException:

this.readableBytes<length

bytesBefore(int index, int length, byte value) int 从当前ByteBuf中查找首次出现value的位置,index<=查找范围<index+length;查找成功返回位置索引,否则返回-1

IndexOutOfBoundsException:

this.readableBytes<index+length

forEachByte(ByteBufProcessor processor); int  遍历当前ByteBuf的可读字节数组,与ByteBufProcessor中设置的查找条件进行比对,从readerIndex开始遍历直到writerIndex。如果满足条件,返回位置索引,否则返回-1  
forEachByte(int index, int length, ByteBufProcessor processor)   遍历当前ByteBuf的可读字节数组,与ByteBufProcessor中设置的查找条件进行比对,从index开始遍历直到index+length。如果满足条件,返回位置索引,否则返回-1  
forEachByteDesc(ByteBufProcessor processor)   逆序遍历当前ByteBuf的可读字节数组,与ByteBufProcessor中设置的查找条件进行比对,从writerIndex-1开始遍历直到readerIndex。如果满足条件,返回位置索引,否则返回-1  
forEachByteDesc(int index, int length, ByteBufProcessor processor)   逆序遍历当前ByteBuf的可读字节数组,与ByteBufProcessor中设置的查找条件进行比对,从index+length-1开始遍历直到index。如果满足条件,返回位置索引,否则返回-1  

Buffer视图

Derived Buffers类似于数据库视图,ByteBuf提供了多个接口用于创建某个ByteBuf的视图或者复制ByteBuf。主要操作如下:

方法名称 返回值 功能说明
duplicate() ByteBuf 返回当前ByteBuf的复制对象,复制后的ByteBuf对象与当前ByteBuf对象共享缓冲区的内容,但是维护自己独立的readerIndex和writerIndex。该操作不修改原ByteBuf的readerIndex和writerIndex。
copy() ByteBuf 从当前ByteBuf复制一个新的ByteBuf对象,复制的新对象缓冲区的内容和索引均是独立的。该操作不修改原ByteBuf的readerIndex和writerIndex。(复制readerIndex到writerIndex之间的内容,其他属性与原ByteBuf相同,如maxCapacity,ByteBufAllocator)
copy(int index, int length) ByteBuf 从当前ByteBuf 指定索引index开始,字节长度为length,复制一个新的ByteBuf对象,复制的新对象缓冲区的内容和索引均是独立的。该操作不修改原ByteBuf的readerIndex和writerIndex。(其他属性与原ByteBuf相同,,如maxCapacity,ByteBufAllocator)
slice() ByteBuf 返回当前ByteBuf的可读子区域,起始位置从readerIndex到writerIndex,返回的ByteBuf对象与当前ByteBuf对象共享缓冲区的内容,但是维护自己独立的readerIndex和writerIndex。该操作不修改原ByteBuf的readerIndex和writerIndex。返回ByteBuf对象的长度为readableBytes()
slice(int index, int length) ByteBuf 返回当前ByteBuf的可读子区域,起始位置从index到index+length,返回的ByteBuf对象与当前ByteBuf对象共享缓冲区的内容,但是维护自己独立的readerIndex和writerIndex。该操作不修改原ByteBuf的readerIndex和writerIndex。返回ByteBuf对象的长度为length

转换为JDK ByteBuffer

当通过NIO的SocketChannel进行网络读写时,操作的对象为JDK的ByteBuffer,因此须在接口层支持netty ByteBuf到JDK的ByteBuffer的相互转换。

方法名称 返回值 功能说明 抛出异常
nioBuffer() ByteBuffer 将当前ByteBuf的可读缓冲区(readerIndex到writerIndex之间的内容)转换为ByteBuffer,两者共享共享缓冲区的内容。对ByteBuffer的读写操作不会影响ByteBuf的读写索引。注意:ByteBuffer无法感知ByteBuf的动态扩展操作。ByteBuffer的长度为readableBytes() UnsupportedOperationException
nioBuffer(int index, int length) ByteBuffer 将当前ByteBuf的可读缓冲区(index到index+length之间的内容)转换为ByteBuffer,两者共享共享缓冲区的内容。对ByteBuffer的读写操作不会影响ByteBuf的读写索引。注意:ByteBuffer无法感知ByteBuf的动态扩展操作。ByteBuffer的长度为length UnsupportedOperationException

随机读写(set和get)

除顺序读写之外,ByteBuf还支持随机读写,其最大的区别在于可随机指定读写的索引位置。

关于随机读写的API这里不再详述。无论set或get,执行前都会进行索引和长度的合法性验证,此外,set操作不同于write的是不支持动态扩展。部分源码:

@Override    public ByteBuf getBytes(int index, byte[] dst) {        getBytes(index, dst, 0, dst.length);        return this;    }    //    @Override    public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {        checkDstIndex(index, length, dstIndex, dst.length);        System.arraycopy(array, index, dst, dstIndex, length);        return this;    }    protected final void checkDstIndex(int index, int length, int dstIndex, int dstCapacity) {        checkIndex(index, length);        if (dstIndex < 0 || dstIndex > dstCapacity - length) {            throw new IndexOutOfBoundsException(String.format(                    "dstIndex: %d, length: %d (expected: range(0, %d))", dstIndex, length, dstCapacity));        }    }    protected final void checkIndex(int index, int fieldLength) {        ensureAccessible();        if (fieldLength < 0) {            throw new IllegalArgumentException("length: " + fieldLength + " (expected: >= 0)");        }        if (index < 0 || index > capacity() - fieldLength) {            throw new IndexOutOfBoundsException(String.format(                    "index: %d, length: %d (expected: range(0, %d))", index, fieldLength, capacity()));        }    }
@Override    public ByteBuf setByte(int index, int value) {        checkIndex(index);        _setByte(index, value);        return this;    }    //索引合法性验证    protected final void checkIndex(int index) {        ensureAccessible();        if (index < 0 || index >= capacity()) {            throw new IndexOutOfBoundsException(String.format(                    "index: %d (expected: range(0, %d))", index, capacity()));        }    }    //确认ByteBuf对象可访问,引用计数器不为0    protected final void ensureAccessible() {        if (refCnt() == 0) {            throw new IllegalReferenceCountException(0);        }    }    //UnpooledHeapByteBuf 实现    @Override    protected void _setByte(int index, int value) {        array[index] = (byte) value;    }
  • 关于ByteBuf继承结构请阅读:

欢迎指出本文有误的地方,转载请注明原文出处

转载于:https://my.oschina.net/7001/blog/742236

你可能感兴趣的文章