中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

細(xì)說 Java 中的字符和字符串( 二 )

2018-07-20    來源:importnew

容器云強(qiáng)勢上線!快速搭建集群,上萬Linux鏡像隨意使用

我們上次在《細(xì)說Java中的字符和字符串(一)》說了Java中char和中文字符之間的關(guān)系,說明了char能不能存儲(chǔ)一個(gè)中文字符,以及如何判斷Java的字符串是否包含中文字符。
這次再看一下MySQL數(shù)據(jù)庫中VARCHAR(N)中的N表示什么,什么會(huì)限制N的大小。然后,從Java的String源代碼分析一下中文字符在Java字符串里是如何存儲(chǔ)的。

VARCHAR(N)中的N代表什么?

和第一篇類似,我們依舊從官方文檔尋找最有權(quán)威的答案。我們從這里可以找到VARCHAR(N)中N代表什么的答案:https://dev.mysql.com/doc/refman/8.0/en/storage-requirements.html

由于原文比較長,這里先把關(guān)鍵片段貼一下:

答案就在這段文字里,我們翻譯一下原文:VARCHAR 或者VARBINARY類型的列最大可存儲(chǔ)的字節(jié)數(shù)不能超過一行的最大可存儲(chǔ)字節(jié)數(shù),也就是65535字節(jié)。如果VARCHAR類型的列存儲(chǔ)的是多字節(jié)類型的字符,那么可存儲(chǔ)的最大字符數(shù)相對就會(huì)變少。比如:utf8mb4類型的字符一個(gè)字符最大可以占到4個(gè)字節(jié),所以一個(gè)VARCHAR類型的字段最多可以存儲(chǔ)16383個(gè)字符(65535/4)。

重點(diǎn)看比如的文字,可以看出來MySQL的VARCHAR(N)中的N代表的是多少個(gè)字符(Character),而Character的對于不同的編碼又代表什么呢?

一起看一下另一篇MySQL官網(wǎng)文檔的內(nèi)容:https://dev.mysql.com/doc/refman/8.0/en/charset-unicode.html

VARCHAR(N)的N值不論是哪種編碼,都對應(yīng)到了字符級(jí)別,也就是這個(gè)列可以存下N個(gè)字符。MySQL的utf8和Java里的utf8不一樣,MySQL的實(shí)現(xiàn)里utf8最大只允許存儲(chǔ)3個(gè)字節(jié)。從上一篇我們知道,utf8編碼最長有4個(gè)字節(jié),那么4個(gè)字節(jié)的utf8字符MySQL的utf8類型是存不下的。

所以,當(dāng)需要存儲(chǔ)emoji表情符的時(shí)候,我們需要用utf8mb4類型的字符集才能存下。MySQL的utf8mb4字符集才能包含全部utf8字符,而MySQL的utf8字符集是一個(gè)不完全版本的utf8字符集。

總結(jié)一下:MySQL中VARCHAR(N)字段類型里邊的N代表最大可以存多少個(gè)字。如果選的是中文編碼,比如utf8編碼,那么N代表最大可以存多少個(gè)漢字。

VARCHAR(N)中的N可以是多大?

N的最大值主要限制因素是MySQL的最大行大小,原文地址在:https://dev.mysql.com/doc/refman/8.0/en/column-count-limit.html。

MySQL的行大小最大不能超過65535bytes,是說MySQL的一行里所有列占用字節(jié)數(shù)的和不能超過65535bytes。BLOB和TEXT比較特別,他們只占用9個(gè)字節(jié)大小,真實(shí)數(shù)據(jù)存儲(chǔ)在行外。

MySQL的uft8類型最多占3個(gè)字節(jié),MySQL允許的最大字符數(shù)是21844(65535/3-1),utf8mb4最多占4個(gè)字節(jié),所以允許的最大字符數(shù)是16382(65535/4-1)。這個(gè)數(shù)字有一點(diǎn)點(diǎn)偏差,因?yàn)閂ARCHAR類型需要1到2個(gè)字節(jié)存儲(chǔ)length,所以最大字符數(shù)可以按照減1計(jì)算。

從Java String分析Java的char和中文的關(guān)系

String有三類構(gòu)造函數(shù),一類是傳入byte[],一類是傳入char[],一類是傳入int[],如下:

public String(byte bytes[], int offset, int length);//字節(jié)流,轉(zhuǎn)成字符串
public String(char value[], int offset, int count);//字符流,轉(zhuǎn)成字符串。較少用,一般用在雙字節(jié)編碼的字節(jié)串轉(zhuǎn)String。
public String(int[] codePoints, int offset, int count);//代碼點(diǎn),轉(zhuǎn)成字符串

String內(nèi)部數(shù)據(jù)存儲(chǔ)使用的是char[]存儲(chǔ),byte 是8字節(jié),char是16字節(jié),int是32字節(jié)。所以byte[]參數(shù)的構(gòu)造函數(shù)會(huì)把byte[]解析成正確的代碼點(diǎn),也就是int類型,再轉(zhuǎn)換成char[]類型存到String內(nèi)部。

所以,我們這里只分析int[]類型入?yún)⒌臉?gòu)造函數(shù),來看一下String是如何把int類型的代碼點(diǎn)轉(zhuǎn)成char[]存起來的。從這里,也能看出來一個(gè)2個(gè)字節(jié)的Unicode和一個(gè)2個(gè)以上字節(jié)的Unicode代碼點(diǎn)是怎么存到String里的。

    public String(int[] codePoints, int offset, int count) {
        //....
        // Pass 1: 計(jì)算int[]轉(zhuǎn)成char[]后的長度
        int n = count;
        for (int i = offset; i < end; i++) {
            int c = codePoints[i];
            if (Character.isBmpCodePoint(c))//如果是BMP范圍的代碼點(diǎn),那么計(jì)數(shù)加1
                continue;
            else if (Character.isValidCodePoint(c))//如果是超出BMP范圍的有效代碼點(diǎn),那么計(jì)數(shù)加2
                n++;
            else throw new IllegalArgumentException(Integer.toString(c));
        }

        // Pass 2: 使用int[]的值填充char[]
        final char[] v = new char[n];

        for (int i = offset, j = 0; i < end; i++, j++) {
            int c = codePoints[i];
            if (Character.isBmpCodePoint(c))//如果是BMP范圍的代碼點(diǎn),直接加入char[]
                v[j] = (char)c;
            else//如果是超出BMP范圍的有效代碼點(diǎn),那么轉(zhuǎn)成2個(gè)char,存入char[]
                Character.toSurrogates(c, v, j++);
        }

        this.value = v;
    }

標(biāo)簽: idc Mysql 代碼 數(shù)據(jù)庫

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點(diǎn)!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請與原作者聯(lián)系。

上一篇:談?wù)勎⑿胖Ц镀爻龅穆┒?/a>

下一篇:CodeReview常見代碼問題