1. 程式人生 > >對Text型別的資料,使用getLength()與getBytes().length獲取的長度不同解析

對Text型別的資料,使用getLength()與getBytes().length獲取的長度不同解析

我們先來看一個小Demo:

Text t = new Text("hadoop");

t.set("pig");

System.out.println(t.getLength());

System.out.println(t.getBytes().length);

不出意外,輸出的結果都是3。但是這個時候如果我們把set方法中的引數改為如下型別將會發生什麼事呢?

t.set(new Text("pig"));

執行程式,結果卻發生了變化,分別輸出了3和6。這是怎麼回事呢?別急,我們通過原始碼看能否得到想要的回答。我們跟蹤set接收的引數型別為Text的方法,如下:

/** copy a text. */

public void set(Text other) {

    set(other.getBytes(), 0, other.getLength());

}

繼續跟進set方法,如下:

public void set(byte[] utf8, int start, int len) {

    setCapacity(len, false);

    System.arraycopy(utf8, start, bytes, 0, len);
    
    this.length = len;

}

我們對當前這個set方法,進行研究一番。首先跟進setCapacity方法:

/*

* Sets the capacity of this Text object to <em>at least</em>

* <code>len</code> bytes. If the current buffer is longer,

* then the capacity and existing content of the buffer are

* unchanged. If <code>len</code> is larger

* than the current capacity, the Text object's capacity is

* increased to match.

* @param len the number of bytes we need

* @param keepData should the old data be kept

*/

private void setCapacity(int len, boolean keepData) {

    if (bytes == null || bytes.length < len) {

        if (bytes != null && keepData) {

            bytes = Arrays.copyOf(bytes, Math.max(len,length << 1));

        } else {

            bytes = new byte[len];

        }

    }

}

通過方法註釋我們很容易知道,當Text當前的buffer長度大於傳過來的len,這個時候buffer的長度和其儲存的內容都是不會發生改變的。但是,如果len大於當前buffer的長度時候,Text物件的長度就需要進行增加。

所以,當我們先通過Text t = new Text("hadoop");建立Text物件的時候,buffer裡面儲存了hadoop,且長度為6。這個時候,我們再使用t.set(new Text("pig"));改變buffer的值的時候,就會呼叫上述的方法。我們知道buffer的長度大於新設定的Text的長度,這個時候,buffer將不會發生任何改變。

緊接著執行System.arraycopy(utf8, start, bytes, 0, len);這是系統本地方法,目的是將utf8按長度複製到bytes(即上述的buffer)中,其餘長度中的不會發生改變。

比如說,將pig複製到hadoop,結果為pigoop。

此時,再通過this.length = len;更新下Text物件的長度。

我們再來回顧下小Demo中的輸出程式中的關鍵方法:

System.out.println(t.getLength());

System.out.println(t.getBytes().length);

對於t.getLength()我們跟程序序很明瞭的知道他是直接返回Text物件的length,即3。

/** Returns the number of bytes in the byte array */

@Override

public int getLength() {

    return length;

}

對於t.getBytes().length,我們是先獲得Text物件的bytes,即pigoop,然後在求出其長度,為6。

但是,問題來了,為什麼使用t.set("pig");的時候長度都是為3呢?很顯然,呼叫的set方法的實現並不相同,我們來看看:

public void set(String string) {

    try {

        ByteBuffer bb = encode(string, true);

        bytes = bb.array();

        length = bb.limit();

   }catch(CharacterCodingException e) {

        throw new RuntimeException("Should not have happened ", e);

    }

}

上面程式碼的第一局將制定的string使用utf-8格式轉化為位元組buffer(Converts the provided String to bytes using the UTF-8 encoding.)。然後,將位元組buffer通過array方法轉化為位元組陣列bytes。並通過limit方法返回buffer的長度賦值給length。此時,無論通過t.getLength();還是t.getBytes().length都將返回相同的長度。