我準(zhǔn)備戰(zhàn)斗到最后敌蜂,不是因?yàn)槲矣赂遥俏蚁胍娮C一切津肛。 --雙雪濤《獵人》
[TOC]
Thinking
- 一個(gè)技術(shù)章喉,為什么要用它,解決了那些問題?
- 如果不用會(huì)怎么樣秸脱,有沒有其它的解決方法落包?
- 對(duì)比其它的解決方案,為什么最終選擇了這種摊唇,都有何利弊咐蝇?
- 你覺得項(xiàng)目中還有那些地方可以用到,如果用了會(huì)帶來那些問題巷查?
- 這些問題你又如何去解決的呢有序?
本文基于Netty 4.1.45.Final-SNAPSHOT
1、概述(Buffer 緩沖區(qū))
? java.nio.Buffer
岛请,一個(gè)Buffer
對(duì)象是固定數(shù)量的數(shù)據(jù)的容器旭寿。實(shí)質(zhì)上是內(nèi)存中的一塊。我們可以向這塊內(nèi)存存取數(shù)據(jù)崇败。
? 緩沖區(qū)的工作與通道精密聯(lián)系的盅称。通道時(shí)I/O傳輸發(fā)生時(shí)通過的入口。而緩沖區(qū)是這些數(shù)據(jù)傳輸?shù)膩碓椿蚰繕?biāo)后室。(可寫可讀的雙向性缩膝。)
? 緩沖區(qū)本質(zhì)上是一塊可以寫入數(shù)據(jù),然后可以從中讀取數(shù)據(jù)的內(nèi)存岸霹。這塊內(nèi)存被包裝成NIO Buffer對(duì)象逞盆。并提供了一組方法。用于方便當(dāng)問該區(qū)域松申。
類圖:- 其實(shí)可以將Buffer理解為一個(gè)數(shù)組的封裝云芦。例如:IntBuffer —>int[]
- MappedByteBuffer 用于實(shí)現(xiàn)內(nèi)存映射文件。
2贸桶、Buffer的基礎(chǔ)使用
- 寫入數(shù)據(jù)到Buffer
- 調(diào)用
flip()
方法 - 從Buffer中讀取數(shù)據(jù)
- 調(diào)用
clear()
方法或者compact()
方法
當(dāng)向buffer寫入數(shù)據(jù)時(shí)舅逸,buffer會(huì)記錄下寫了多少數(shù)據(jù)。一旦要讀取數(shù)據(jù)皇筛,需要通過flip()方法將Buffer從寫模式切換到讀模式琉历。在讀模式下,可以讀取之前寫入到buffer的所有數(shù)據(jù)水醋。
一旦讀完了所有的數(shù)據(jù)旗笔,就需要清空緩沖區(qū),讓它可以再次被寫入拄踪。有兩種方式能清空緩沖區(qū):調(diào)用clear()或compact()方法蝇恶。clear()方法會(huì)清空整個(gè)緩沖區(qū)。compact()方法只會(huì)清除已經(jīng)讀過的數(shù)據(jù)惶桐。任何未讀的數(shù)據(jù)都被移到緩沖區(qū)的起始處撮弧,新寫入的數(shù)據(jù)將放到緩沖區(qū)未讀數(shù)據(jù)的后面潘懊。(這種定義可以理解為,緩沖區(qū)本身維護(hù)著一個(gè)類似于隊(duì)列的數(shù)據(jù)結(jié)構(gòu)贿衍,先進(jìn)先出原則)
/**
* Buffer 基本使用
*
* @author by Mr. Li
* @date 2020/2/11 12:23
*/
@Slf4j
public class BufferExample {
public static void main(String[] args) throws Exception {
RandomAccessFile accessFile = new RandomAccessFile("E:/idea_workspace/springcloud2.0/netty/netty-mytest/src/main/resources/data/nio-data.txt", "rw");
// 獲取 NIO 文件通道
FileChannel channel = accessFile.getChannel();
// 獲取緩沖區(qū)Buffer
ByteBuffer byteBuffer = ByteBuffer.allocate(48);
int count = channel.read(byteBuffer);// read into buffer.
while (count != -1) {
// make buffer ready for read
byteBuffer.flip();
while (byteBuffer.hasRemaining()) {
log.info("read 1 byte at a time : {}", byteBuffer.get());
}
byteBuffer.clear(); // make buffer ready for writing .即清空緩沖區(qū)授舟,是Buffer又可以讀寫數(shù)據(jù)
count = channel.read(byteBuffer);
}
// 關(guān)閉文件
accessFile.close();
}
}
3、Buffer 屬性
? Buffer緩沖區(qū)中提供了四個(gè)屬性贸辈。用于來提供其包含的數(shù)據(jù)元素的信息释树。
容量(Capacity)
? 緩沖區(qū)能夠容納的數(shù)據(jù)元素的最大數(shù)量。這一容量在緩沖區(qū)被初始化時(shí)擎淤,就會(huì)被創(chuàng)建躏哩,并且永遠(yuǎn)不會(huì)改變。
上界(Limit)
? 緩沖區(qū)的第一個(gè)不能被讀或?qū)懙脑厝嗳肌#梢岳斫鉃榫彌_區(qū)中現(xiàn)有可讀的數(shù)據(jù))
位置(Position)
? 下一個(gè)要被讀或?qū)懙脑氐乃饕ǔ摺#ㄔ搶傩员?code>#get()``#put()自動(dòng)維護(hù))
標(biāo)記(Mark)
? 一個(gè)備忘位置。調(diào)用#mark()
來設(shè)定mark = position
炊汤。調(diào)用#reset()
設(shè)定position = mark
正驻。標(biāo)記在設(shè)定前是未定義的(undefined)
。
源碼
public abstract class Buffer {
/**
* The characteristics of Spliterators that traverse and split elements
* maintained in Buffers.
*/
static final int SPLITERATOR_CHARACTERISTICS =
Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.ORDERED;
// Invariants: mark <= position <= limit <= capacity
private int mark = -1;
private int position = 0;
private int limit;
private int capacity;
// Used only by direct buffers
// 僅由直接緩沖區(qū)使用
// NOTE: hoisted here for speed in JNI GetDirectBufferAddress
long address;
// Creates a new buffer with the given mark, position, limit, and capacity,
// after checking invariants.
//
Buffer(int mark, int pos, int lim, int cap) { // package-private
if (cap < 0)
throw new IllegalArgumentException("Negative capacity: " + cap);
this.capacity = cap;
limit(lim);
position(pos);
if (mark >= 0) {
if (mark > pos)
throw new IllegalArgumentException("mark > position: ("
+ mark + " > " + pos + ")");
this.mark = mark;
}
}
//....doSomething
從源碼可以看出四種屬性的關(guān)系:
mark <= position <= limit <= capacity
0 <= mark <= position <= limit <= capacity
Buffer四種屬性圖解
? Buffer緩沖區(qū)是分讀寫模式的抢腐。(使用filp() 切換讀寫模式)
porsition和limit的含義取決于Buffer處在讀模式還是寫模式姑曙。不管Buffer處在什么模式,capacity的含義總是一樣的迈倍。
寫模式
- 假設(shè)定義的ByteBuffer對(duì)象伤靠。(長(zhǎng)度為10 的緩沖區(qū)長(zhǎng)度
ByteBuffer.allocate(10);
) - 此時(shí)創(chuàng)建出來的Buffer對(duì)象 Limit 和capacity為指向內(nèi)存末端,數(shù)值為9啼染。
代碼示例如下:
/**
* Buffer 讀寫模式切換即 屬性賦值變化宴合。
* @throws Exception
*/
@Test
public void bufferTest() throws Exception {
// 初始化 長(zhǎng)度為10 的Buffer
ByteBuffer byteBuffer = ByteBuffer.allocate(10);
RandomAccessFile accessFile = new RandomAccessFile("E:/idea_workspace/springcloud2.0/netty/netty-mytest/src/main/resources/data/buf-data.txt", "rw");
// 獲取 文件通道
FileChannel channel = accessFile.getChannel();
// 將通道的中的數(shù)據(jù)讀取到緩沖區(qū)中
int i = channel.read(byteBuffer);
while (i != -1) {
// 切換 成讀模式
byteBuffer.flip();
while (byteBuffer.hasRemaining()) {
log.info("write -> read {}", byteBuffer.get());
}
byteBuffer.clear();
// 確保 數(shù)據(jù)讀取完畢。返回-1
i = channel.read(byteBuffer);
}
accessFile.close();
}
Debug查看屬性變化:
讀模式
總結(jié)一下
- 從上述讀寫切換可以看出
- 此內(nèi)存區(qū)域?qū)崉t可以看作是一塊數(shù)組內(nèi)存區(qū)域迹鹅。在初始化時(shí)卦洽,capacity是被固定的,用來標(biāo)識(shí)內(nèi)存的容量斜棚,可存放的最大元素?cái)?shù)阀蒂。并且不管讀寫如何切換,capacity是不會(huì)改變的弟蚀。
- Limit 在讀寫模式下的含義(上限)
- 寫模式:即在緩存被初始化時(shí)(
ByteBuffer.allocate(10);
)Limit就指向了內(nèi)存的最大容量與capacity相等蚤霞。 - 讀模式:當(dāng)調(diào)用
#filp()
切換為讀模式后,limit就會(huì)指向內(nèi)存中的實(shí)際容量义钉,此時(shí)position就會(huì)指向下一個(gè)內(nèi)存中即將被讀的索引位置昧绣。
- 寫模式:即在緩存被初始化時(shí)(
- position 永遠(yuǎn)指向下一個(gè)即將被寫/讀的索引位置。初始值為0断医。
-
寫模式下滞乙,每往 Buffer 中寫入一個(gè)值奏纪,
position
就自動(dòng)加 1 鉴嗤,代表下一次的寫入位置斩启。 -
讀模式下,每從 Buffer 中讀取一個(gè)值醉锅,
position
就自動(dòng)加 1 兔簇,代表下一次的讀取位置。( 和寫模式類似 )
-
寫模式下滞乙,每往 Buffer 中寫入一個(gè)值奏纪,
- mark 標(biāo)記硬耍,通過
#mark()
方法垄琐,記錄當(dāng)前position
;通過#reset()
恢復(fù)position
為標(biāo)記经柴。- 寫模式下狸窘,標(biāo)記上一次寫位置。
- 讀模式下坯认,標(biāo)記上一次讀位置翻擒。
- 所以從代碼層次上充分的體現(xiàn)了四種屬性的關(guān)系
- limit最大只能與 capacity相等。
- 最小則是緩沖區(qū)為空牛哺。
- position則是四大屬性中陋气,最善變的一個(gè),一直隨將要讀寫的操作變化著引润。
- mark 則永遠(yuǎn)都不會(huì)超過position巩趁。并且初始化下的值為-1.
- limit最大只能與 capacity相等。
mark <= positioon <= limit <= capacity
思考
? 在這種反轉(zhuǎn)切換讀寫的模式下,真的非常的繁瑣淳附。操作復(fù)雜议慰。完全可以使用獨(dú)立的標(biāo)記,用于標(biāo)記讀寫不同的操作奴曙。類似于Netty使用的模式褒脯,就是摒棄了這種反轉(zhuǎn)的操作。
? Netty的ByteBuf下優(yōu)雅的設(shè)計(jì)
0 <= readerIndex <= writerIndex <= capacity
4缆毁、創(chuàng)建Buffer
? 1. 每個(gè)Buffer實(shí)現(xiàn)類番川,都相應(yīng)的提供了#allocate(int capacity)
靜態(tài)方法。
/**
* Allocates a new byte buffer. Allocates a new direct byte buffer.
*
* <p> The new buffer's position will be zero, its limit will be its
* capacity, its mark will be undefined, and each of its elements will be
* initialized to zero. It will have a {@link #array backing array},
* and its {@link #arrayOffset array offset} will be zero.
*
* @param capacity
* The new buffer's capacity, in bytes
*
* @return The new byte buffer
*
* @throws IllegalArgumentException
* If the <tt>capacity</tt> is a negative integer
*/
public static ByteBuffer allocate(int capacity) {
if (capacity < 0)
throw new IllegalArgumentException();
return new HeapByteBuffer(capacity, capacity);
}
由于ByteBuffer 為抽象類脊框,返回的是它基于堆內(nèi)(Non-Direct)內(nèi)存的實(shí)現(xiàn)類HeapByteBuffer的對(duì)象颁督。
HeapByteBuffer(int cap, int lim) { // package-private
super(-1, 0, lim, cap, new byte[cap], 0);
/*
hb = new byte[cap];
offset = 0;
*/
}
// 這里可以清晰的看出,Buffer 其實(shí)質(zhì)就是一個(gè)內(nèi)存數(shù)組浇雹。用于存儲(chǔ)數(shù)據(jù)
- 每個(gè) Buffer 實(shí)現(xiàn)類沉御,都提供了
#wrap(array)
靜態(tài)方法,幫助我們將其對(duì)應(yīng)的數(shù)組包裝成一個(gè) Buffer 對(duì)象昭灵。還是以 ByteBuffer 舉例子吠裆,代碼如下:
// ByteBuffer.java Allocates a new direct byte buffer.
public static ByteBuffer wrap(byte[] array,int offset, int length){
try {
return new HeapByteBuffer(array, offset, length);
} catch (IllegalArgumentException x) {
throw new IndexOutOfBoundsException();
}
}
public static ByteBuffer wrap(byte[] array) {
return wrap(array, 0, array.length);
}
- 和
#allocate(int capacity)
靜態(tài)方法一樣伐谈,返回的也是 HeapByteBuffer 的對(duì)象。
為什么Buffer要?jiǎng)?chuàng)建為 Direct Buffer
Direct Buffer 與Non-Direct Buffer 的區(qū)別
FROM 《Java NIO 的前生今世 之三 NIO Buffer 詳解》
Direct Buffer:
- 所分配的內(nèi)存不在 JVM 堆上, 不受 GC 的管理.(但是 Direct Buffer 的 Java 對(duì)象是由 GC 管理的, 因此當(dāng)發(fā)生 GC, 對(duì)象被回收時(shí), Direct Buffer 也會(huì)被釋放)
- 因?yàn)?Direct Buffer 不在 JVM 堆上分配, 因此 Direct Buffer 對(duì)應(yīng)用程序的內(nèi)存占用的影響就不那么明顯(實(shí)際上還是占用了這么多內(nèi)存, 但是 JVM 不好統(tǒng)計(jì)到非 JVM 管理的內(nèi)存.)
- 申請(qǐng)和釋放 Direct Buffer 的開銷比較大. 因此正確的使用 Direct Buffer 的方式是在初始化時(shí)申請(qǐng)一個(gè) Buffer, 然后不斷復(fù)用此 buffer, 在程序結(jié)束后才釋放此 buffer.
- 使用 Direct Buffer 時(shí), 當(dāng)進(jìn)行一些底層的系統(tǒng) IO 操作時(shí), 效率會(huì)比較高, 因?yàn)榇藭r(shí) JVM 不需要拷貝 buffer 中的內(nèi)存到中間臨時(shí)緩沖區(qū)中.
Non-Direct Buffer:
- 直接在 JVM 堆上進(jìn)行內(nèi)存的分配, 本質(zhì)上是 byte[] 數(shù)組的封裝.
- 因?yàn)?Non-Direct Buffer 在 JVM 堆中, 因此當(dāng)進(jìn)行操作系統(tǒng)底層 IO 操作中時(shí), 會(huì)將此 buffer 的內(nèi)存復(fù)制到中間臨時(shí)緩沖區(qū)中. 因此 Non-Direct Buffer 的效率就較低.
總結(jié)對(duì)比:
- 之所以使用堆外內(nèi)存试疙,是為了避免每次使用buffe如對(duì)象時(shí)诵棵,都會(huì)將此對(duì)象復(fù)制到中間林是緩沖區(qū)中,因此Non-Direct Buffer效率會(huì)非常低下祝旷。
- 堆外內(nèi)存(直接內(nèi)存--direct byte buffer)則可以直接使用履澳,避免了對(duì)象的復(fù)制,提高了效率怀跛。
5距贷、寫入數(shù)據(jù)
? 每個(gè)Buffer的實(shí)現(xiàn)類,都可以基于Channel來寫入數(shù)據(jù)吻谋,但每個(gè)實(shí)現(xiàn)類也單獨(dú)的提供了寫入數(shù)據(jù)的方法#put(...)
忠蝗。向Buffer寫入數(shù)據(jù),以ByteBuffer
舉例子漓拾。
/**
* buffer 的 讀寫 操作
*/
@Test
public void bufferTest02() throws Exception {
log.info("Write is coming.this is two method");
// Buffer 的寫 有兩種阁最,一種基于 Channel 一種是自己提供的#put()方法
ByteBuffer byteBuffer = ByteBuffer.allocate(48);
byteBuffer.put((byte) 1); // position = 1
// 獲取 文件Channel
RandomAccessFile accessFile = new RandomAccessFile("E:/idea_workspace/springcloud2.0/netty/netty-mytest/src/main/resources/data/buf-data.txt", "rw");
// 將Channel 中的數(shù)據(jù)寫入Buffer 中
FileChannel channel = accessFile.getChannel();
int readResult = channel.read(byteBuffer);// position = 4
log.info("Read is coming。晦攒。闽撤。。");
while (readResult != -1) {
// Write -> Read
byteBuffer.flip();
/**
* public final boolean hasRemaining() {
* return position < limit;
* }
* 用來判斷 隊(duì)首是否還有未讀數(shù)據(jù)脯颜。
*/
while (byteBuffer.hasRemaining()) {
log.info("byteBuffer read ready -> {}", byteBuffer.get());
}
byteBuffer.clear(); // 清除/并且重置到初始化狀態(tài)哟旗。寫狀態(tài)
readResult = channel.read(byteBuffer);
}
accessFile.close();
}
}
上述代碼,提供了兩種向Buffer 寫入數(shù)據(jù)的方式栋操。
兩種方式闸餐,分別的豐富了Buffer 的實(shí)用性。Channle則是滿足了來自各個(gè)網(wǎng)絡(luò)或文件等外部資源的輸入矾芙。
int num = channel.read(buffer);
// 返回的是從Channel中寫入到Buffer的數(shù)據(jù)大小
這里需要注意的是:在NIO 中讀Buffer 的讀寫操作舍沙。
? 當(dāng)Channel調(diào)用
#read()
方法時(shí),實(shí)則是Buffer示例的寫入操作剔宪。(需要重點(diǎn)明確拂铡。)? 因?yàn)樵谶@里所謂的讀寫操作都是先對(duì)于Buffer示例而言的。所以不要看到調(diào)用的方法是read()葱绒。實(shí)則是寫入操作感帅。與Buffer而言。
6地淀、讀取數(shù)據(jù)
? 每個(gè)Buffer實(shí)現(xiàn)類失球,都提供了#get(...)
方法,從Buffer讀取數(shù)據(jù)帮毁。
// 讀取 byte
public abstract byte get();
public abstract byte get(int index);
// 讀取 byte 數(shù)組
public ByteBuffer get(byte[] dst, int offset, int length) {...}
public ByteBuffer get(byte[] dst) {...}
// ... 省略实苞,還有其他 get 方法
對(duì)于 Buffer 來說豺撑,還有一個(gè)非常重要的操作就是,我們要講來向 Channel 的寫入 Buffer 中的數(shù)據(jù)黔牵。在系統(tǒng)層面上聪轿,這個(gè)操作我們稱為寫操作,因?yàn)閿?shù)據(jù)是從內(nèi)存中寫入到外部( 文件或者網(wǎng)絡(luò)等 )荧止。示例如下:
int num = channel.write(buffer);
-
上述方法會(huì)返回向 Channel 中寫入 Buffer 的數(shù)據(jù)大小屹电。對(duì)應(yīng)方法的代碼如下:
public interface WritableByteChannel extends Channel { public int write(ByteBuffer src) throws IOException; }
7阶剑、rewind() / flip()/clear()
7.1跃巡、filp
? #filp()
將Buffer寫狀態(tài)切換成度狀態(tài)。
/**
* Flips this buffer. The limit is set to the current position and then
* the position is set to zero. If the mark is defined then it is
* discarded.
反轉(zhuǎn)整個(gè)緩沖區(qū)牧愁,將limit設(shè)置為當(dāng)前的position(即為當(dāng)前緩沖區(qū)的實(shí)際數(shù)據(jù)容量)素邪,然后將position設(shè)置為0,如果使用了標(biāo)記mark猪半,將其拋棄兔朦,設(shè)置為初始值-1。
*
* <p> After a sequence of channel-read or <i>put</i> operations, invoke
* this method to prepare for a sequence of channel-write or relative
* <i>get</i> operations. For example:
*
* <blockquote><pre>
* buf.put(magic); // Prepend header
* in.read(buf); // Read data into rest of buffer
* buf.flip(); // Flip buffer
* out.write(buf); // Write header + data to channel</pre></blockquote>
*
* <p> This method is often used in conjunction with the {@link
* java.nio.ByteBuffer#compact compact} method when transferring data from
* one place to another. </p>
*
* @return This buffer
*/
public final Buffer flip() {
limit = position; // 設(shè)置讀取上限
position = 0; // 重置position
mark = -1; // 清空mark
return this;
}
示例代碼磨确,如下:
@Test
public void flipTest() throws Exception {
RandomAccessFile accessFile = new RandomAccessFile("E:/idea_workspace/springcloud2.0/netty/netty-mytest/src/main/resources/data/buf-data.txt", "rw");
FileChannel channel = accessFile.getChannel();
ByteBuffer allocate = ByteBuffer.allocate(48);
allocate.put("magic".getBytes());
allocate.flip();
channel.write(allocate);
log.info("channel 當(dāng)前容量為{}",channel.position());
}
7.2沽甥、rewind
? #rewind()
方法,可以重置 position
的值為 0 乏奥。因此摆舟,我們可以重新讀取和寫入 Buffer 了。
大多數(shù)情況下邓了,該方法主要針對(duì)于讀模式恨诱,所以可以翻譯為“倒帶”。也就是說骗炉,和我們當(dāng)年的磁帶倒回去是一個(gè)意思照宝。(意思就是璃哟,重置緩沖區(qū)中的數(shù)據(jù)斑匪。)代碼如下:
public final Buffer rewind() {
position = 0; // 重置 position
mark = -1; // 清空 mark
return this;
}
從代碼上,和 #flip()
相比嬉愧,非常類似乍丈,除了少了第一行的 limit = position
的代碼塊剂碴。
使用示例,代碼如下:
channel.write(buf); // Write remaining data
buf.rewind(); // Rewind buffer
buf.get(array); // Copy data into array
7.3诗赌、clear
? #clear()
方法汗茄,可以“重置” Buffer 的數(shù)據(jù)。因此铭若,我們可以重新讀取和寫入 Buffer 了洪碳。
大多數(shù)情況下递览,該方法主要針對(duì)于寫模式。代碼如下:
public final Buffer clear() {
position = 0; // 重置 position
limit = capacity; // 恢復(fù) limit 為 capacity
mark = -1; // 清空 mark
return this;
}
- 從源碼上瞳腌,我們可以看出绞铃,Buffer 的數(shù)據(jù)實(shí)際并未清理掉,所以使用時(shí)需要注意嫂侍。
- 讀模式下儿捧,盡量不要調(diào)用
#clear()
方法,因?yàn)?limit
可能會(huì)被錯(cuò)誤的賦值為capacity
挑宠。相比來說菲盾,調(diào)用#rewind()
更合理,如果有重讀的需求各淀。
使用示例懒鉴,代碼如下:
buf.clear(); // Prepare buffer for reading
in.read(buf); // Read data
8、 mark() 搭配 reset()
8.1 mark
#mark()
方法碎浇,保存當(dāng)前的 position
到 mark
中临谱。代碼如下:
public final Buffer mark() {
mark = position;
return this;
}
- 唯一的設(shè)置 標(biāo)記位的方法。
8.2 reset
#reset()
方法奴璃,恢復(fù)當(dāng)前的 postion
為 mark
悉默。代碼如下:
public final Buffer reset() {
int m = mark;
if (m < 0)
throw new InvalidMarkException();
position = m;
return this;
}
- 恢復(fù)到標(biāo)記位,有類似于秒表的功能苟穆,撤回到標(biāo)記位抄课。并且可重新設(shè)置標(biāo)記位后面的值。
9 鞭缭、hasRemaining
? 多半使用在讀操作中剖膳,用作判斷緩沖區(qū)中是否還有可讀數(shù)據(jù)。(可想而知:是直接判斷 下個(gè)即將要讀數(shù)據(jù)的索引位置與上限做比較岭辣。如果相等則沒有可讀數(shù)據(jù) return position < limit
)
/**
* Tells whether there are any elements between the current position and
* the limit.
*告訴當(dāng)前位置和上限之間是否有任何元素
* @return <tt>true</tt> if, and only if, there is at least one element
* remaining in this buffer
*/
public final boolean hasRemaining() {
return position < limit;
}
10吱晒、equals()與compareTo()方法
10.1、equals()
? 當(dāng)滿足下列條件時(shí)沦童,表示兩個(gè)Buffer相等:
- 有相同的類型(byte仑濒、char、int 等)
- Buffer中剩余的Byte偷遗、char等的個(gè)數(shù)相同墩瞳。
- Buffer中所有剩余的byte、char等都相同氏豌。
如你所見喉酌,equals只是比較Buffer的一部分,不是每一個(gè)在它里面的元素都比較。實(shí)際上泪电,它只比較Buffer中的剩余元素般妙。
10.2、compareTo()
compareTo()方法比較兩個(gè)Buffer的剩余元素(byte相速、char等)碟渺, 如果滿足下列條件,則認(rèn)為一個(gè)Buffer“小于”另一個(gè)Buffer:
- 第一個(gè)不相等的元素小于另一個(gè)Buffer中對(duì)應(yīng)的元素 突诬。
- 所有元素都相等苫拍,但第一個(gè)Buffer比另一個(gè)先耗盡(第一個(gè)Buffer的元素個(gè)數(shù)比另一個(gè)少)。
(譯注:剩余元素是從 position到limit之間的元素)
其它源碼相對(duì)簡(jiǎn)單旺隙。不一一介紹了绒极。
本文僅供筆者本人學(xué)習(xí),有錯(cuò)誤的地方還望指出催束,一起進(jìn)步集峦!望海涵伏社!
歡迎關(guān)注我的公共號(hào)抠刺,無廣告,不打擾摘昌。不定時(shí)更新Java后端知識(shí)速妖,我們一起超神。
qrcode.jpg——努力努力再努力xLg
加油聪黎!