美團面試官問我一個字符的String.length()是多少,我說是1,面試官說你回去好好學一下吧


本文首發於微信公眾號:程序員喬戈里






public class testT {
    public static void main(String [] args){
        String A = "hi你是喬戈里";
        System.out.println(A.length());
    }
}

以上結果輸出為7。




小萌邊說邊在IDEA中的win環境下選中String.length()函數,使用ctrl+B快捷鍵進入到String.length()的定義。

    /**
     * Returns the length of this string.
     * The length is equal to the number of <a href="Character.html#unicode">Unicode
     * code units</a> in the string.
     *
     * @return  the length of the sequence of characters represented by this
     *          object.
     */
    public int length() {
        return value.length;
    }

接着使用google翻譯對這段英文進行了翻譯,得到了大體意思:返回字符串的長度,這一長度等於字符串中的 Unicode 代碼單元的數目。

小萌:喬戈里,那這又是啥意思呢?
喬哥:前幾天我寫的一篇文章:面試官問你編碼相關的面試題,把這篇甩給他就完事!里面對於Java的字符使用的編碼有介紹:

Java中 有內碼和外碼這一區分簡單來說

  • 內碼:char或String在內存里使用的編碼方式。
  • 外碼:除了內碼都可以認為是“外碼”。(包括class文件的編碼)

而java內碼:unicode(utf-16)中使用的是utf-16.
所以上面的那句話再進一步解釋就是:返回字符串的長度,這一長度等於字符串中的UTF-16的代碼單元的數目。


代碼單元指一種轉換格式(UTF)中最小的一個分隔,稱為一個代碼單元(Code Unit),因此,一種轉換格式只會包含整數個單元。UTF-X 中的數字 X 就是各自代碼單元的位數。

UTF-16 的 16 指的就是最小為 16 位一個單元,也即兩字節為一個單元,UTF-16 可以包含一個單元和兩個單元,對應即是兩個字節和四個字節。我們操作 UTF-16 時就是以它的一個單元為基本單位的。

你還記得你前幾天被面試官說菜的時候學到的Unicode知識嗎,在面試官讓我講講Unicode,我講了3秒說沒了,面試官說你可真菜這里面提到,UTF-16編碼一個字符對於U+0000-U+FFFF范圍內的字符采用2字節進行編碼,而對於字符的碼點大於U+FFFF的字符采用四字節進行編碼,前者是兩字節也就是一個代碼單元,后者一個字符是四字節也就是兩個代碼單元!

而上面我的例子中的那個字符的Unicode值就是“U+1D11E”,這個Unicode的值明顯大於U+FFFF,所以對於這個字符UTF-16需要使用四個字節進行編碼,也就是使用兩個代碼單元!

所以你才看到我的上面那個示例結果表示一個字符的String.length()長度是2!




來看個例子!

public class testStringLength {
    public static void main(String [] args){
        String B = "𝄞"; // 這個就是那個音符字符,只不過由於當前的網頁沒支持這種編碼,所以沒顯示。
        String C = "\uD834\uDD1E";// 這個就是音符字符的UTF-16編碼
        System.out.println(C);
        System.out.println(B.length());
        System.out.println(B.codePointCount(0,B.length()));
        // 想獲取這個Java文件自己進行演示的,可以在我的公眾號【程序員喬戈里】后台回復 6666 獲取
    }
}

可以看到通過codePointCount()函數得知這個音樂字符是一個字符!

幾個問題:
0.codePointCount是什么意思呢?
1.之前不是說音符字符是“U+1D11E”,為什么UTF-16是"\uD834\uDD1E",這倆之間如何轉換?
2.前面說了UTF-16的代碼單元,UTF-32和UTF-8的代碼單元是多少呢?

一個一個解答:

第0個問題:

codePointCount其實就是代碼點數的意思,也就是一個字符就對應一個代碼點數。

比如剛才音符字符(沒辦法打出來),它的代碼點是U+1D11E,但它的代理單元是U+D834和U+DD1E,如果令字符串str = "\u1D11E",機器識別的不是音符字符,而是一個代碼點”/u1D11“和字符”E“,所以會得到它的代碼點數是2,代碼單元數也是2。

但如果令字符str = "\uD834\uDD1E",那么機器會識別它是2個代碼單元代理,但是是1個代碼點(那個音符字符),故而,length的結果是代碼單元數量2,而codePointCount()的結果是代碼點數量1.

第1個問題

上圖是對應的轉換規則:

  • 首先 U+1D11E-U+10000 = U+0D11E
  • 接着將U+0D11E轉換為二進制:0000 1101 0001 0001 1110,前10位是0000 1101 00 后10位是01 0001 1110
  • 接着套用模板:110110yyyyyyyyyy 110111xxxxxxxxxx
  • U+0D11E的二進制依次從左到右填入進模板:110110 0000 1101 00 110111 01 0001 1110
  • 然后將得到的二進制轉換為16進制:d834dd1e,也就是你看到的utf-16編碼了

第2個問題

  • 同理,UTF-32 以 32 位一個單元,它只包含這一種單元就夠了,它的一單元自然也就是四字節了。
  • UTF-8 的 8 指的就是最小為 8 位一個單元,也即一字節為一個單元,UTF-8 可以包含一個單元,二個單元,三個單元及四個單元,對應即是一,二,三及四字節。

參考

本文首發於微信公眾號:程序員喬戈里

如果是頭條用戶,可以在我的頭條號程序員喬戈里后台回復 資源獲取價值59998元的編程和考研資料
覺得文章不錯的歡迎關注我的WX公眾號:程序員喬戈里
我是BAT大廠后台開發工程師,,專注分享技術干貨/編程資源/求職面試/成長感悟等,關注送5000G編程資源和自己整理的一份幫助不少人拿下java的offer的面經附答案,免費下載CSDN資源。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM