Java char类型介绍
前言:最近,想寫一篇關(guān)于介紹產(chǎn)生”亂碼問題“根本原因的文章,因此,查看了Java中的字符是如何存儲(chǔ)的,即char數(shù)據(jù)類型。在此將學(xué)到的知識(shí)做一個(gè)總結(jié)。
一、char數(shù)據(jù)類型
char類型最初用于表示Unicode字符集中的一個(gè)字符,但是隨著Unicode標(biāo)準(zhǔn)的不斷發(fā)展,其字符集不斷擴(kuò)展,表示的字符隨之增加,已經(jīng)超出了16位的char類型可以表示的范圍(65535),現(xiàn)今,char類型用于表示一個(gè)代碼單元。有些Unicode字符需要使用一個(gè)代碼單元表示,有些Unicdoe字符需要兩個(gè)代碼單元表示。關(guān)于代碼單元的概念,下文會(huì)詳細(xì)介紹,這里先有一個(gè)印象即可。
1. 字面量值
字面量值需要單引號(hào)''括起來,單引號(hào)中必須有值,其形式如下:
- 單個(gè)Unicode字符,最常見的形式,例如,'A'、'中';
- 轉(zhuǎn)義序列\(zhòng)u,范圍\u0000~\uFFFF,例如, '\u2122' 表示字符?,'\u03C0'表示字符'π';
- 特殊字符的轉(zhuǎn)義序列,例如'\n'表示換行,'\''表示單引號(hào)。
轉(zhuǎn)義字符,一般是不可打印的或者與語言的語法字符產(chǎn)生了沖突。
二、Unicode字符集
1. 字符集和編碼規(guī)則
我們經(jīng)常會(huì)聽到Unicode、UTF-8、UTF-16這些術(shù)語,然而,它們是完全不同的概念。Unicode是字符集,UTF-8、UTF-16是編碼規(guī)則,具體概念如下:
字符集:為每一個(gè)「字符」分配了一個(gè)唯一的 ID或者編號(hào)(稱為為碼位 / 碼點(diǎn) Code Point)
編碼規(guī)則:將「編號(hào)」轉(zhuǎn)換為字節(jié)序列的規(guī)則
例如,‘中’ 的碼點(diǎn)如下
其使用不同編碼規(guī)則,進(jìn)行編碼的結(jié)果如下
2. Unicode字符集
Java設(shè)計(jì)之初Unicode字符集中的字符個(gè)數(shù)還不到65536的一半,所以使用16位的char類型完全可以表示所有字符,但是,隨著中、日、韓等其它字符的加入,導(dǎo)致Unicode字符集中的字符個(gè)數(shù)超過了65535,此時(shí)char類型已經(jīng)無法表示Unicode字符集中的所有字符了。
我們先介紹一些必備的基礎(chǔ)知識(shí)。
碼點(diǎn)表示了一個(gè)字符的ID或者編號(hào),在Unicode標(biāo)準(zhǔn)中,采用十六進(jìn)制書寫,并加上前綴U+,例如U+0041(轉(zhuǎn)換為十進(jìn)制即65),表示字母A的碼點(diǎn)。
把Unicoee字符分為17個(gè)平面,每個(gè)平面包含不同種類的字符。
基本的多語言平面,碼點(diǎn)范圍U+0000~U+FFFF,表示了我們各個(gè)國家常用的字符,也是開始的char類型可以表示的字符。
其他平面(1到16號(hào)平面),碼點(diǎn)范圍U+10000~U+10FFFF,表示輔助字符,例如我們的不常用的繁體字等等,char類型無法直接表示這些字符,例如,char = '‘𝕆’ 會(huì)編譯報(bào)錯(cuò)( 𝕆,一個(gè)數(shù)學(xué)符號(hào),Unicdoe字符碼點(diǎn) U+1D546)
那么,char如何表示碼點(diǎn)在U+10000~U+10FFFF之間的Unicode字符呢?
它借鑒了UTF-16編碼規(guī)則。
UTF-16使用不同長度的編碼表示所有Unicode字符。在基本的多語言平面中,使用16位表示一個(gè)字符,稱為代碼單元,而其他平面的輔助字符需要使用32位,也就是一對代碼單元表示一個(gè)字符。
U+D800~U+DBFF表示第一個(gè)代碼單元,U+DC00~U+DFFF表示第二個(gè)代碼單元。
U+D800~U+DFFF,這一段碼點(diǎn)稱為替換區(qū)域,可以看出它屬于基本的多語言平面(U+0000~U+FFFF)的范圍,為了避免產(chǎn)生歧義或沖突,替換區(qū)域的碼點(diǎn)沒有沒配給任何字符。
假設(shè)為替換區(qū)域碼點(diǎn)分配了字符,就無法判斷該碼點(diǎn)是表示一個(gè)字符,還是輔助字符的第一個(gè)代碼單元或第二個(gè)代碼單元。
具體讓我們看一下如何表示字符 ‘?’ (Unicdoe字符碼點(diǎn) U+1D546)?
第一個(gè)代碼單元:D800到DBFF
1101 1000 0000 0000
1101 1011 1111 1111
110110XXXXXXXXXX 可以編碼10位二進(jìn)制數(shù)
第二個(gè)代碼單元:DC00到DFFF
1101 1100 0000 0000
1101 1111 1111 1111
110111XXXXXXXXXX 可以編碼10位二進(jìn)制數(shù)
U+10000到U+10FFFF 可以看出轉(zhuǎn)換成二進(jìn)制樹最多有21位,但是我們加起來最多可以編碼20位二進(jìn)制數(shù),怎么辦?
將范圍偏移-10000,范圍變成了U+0000到U+FFFFF,如此,就滿足20位編碼了。
? U+1D546 偏移后U+D546
1101 0101 0100 0110
后十位“01 0100 0110"放入第二個(gè)代碼單元110111XXXXXXXXXX:1101 1101 0100 0110,對應(yīng)的十六進(jìn)制數(shù):DD46
前十位(不足十位首部補(bǔ)0)00001101 01 放入第一個(gè)代碼單元110110XXXXXXXXXX:1101 1000 0011 0101,對應(yīng)的十六進(jìn)制數(shù)是:D835
因此,?,U+1D546使用兩個(gè)代碼單元表示:D835 DD46
我們在程序中如何存儲(chǔ)碼點(diǎn)在U+10000到U+10FFFF之間的字符呢?
直接存儲(chǔ)字符字面量值或者轉(zhuǎn)義序列\(zhòng)u,編譯報(bào)錯(cuò)。很容易理解char類型16位正好只能存儲(chǔ)一個(gè)代碼單元,而該字符需要兩個(gè)代碼單元表示,無法用char類型直接表示該字符。
總結(jié):現(xiàn)在,char類型用于描述一個(gè)代碼單元。對于基本的多語言平面中的字符(碼點(diǎn)范圍U+0000到U+FFFF,不包含替換區(qū)域)可以使用一個(gè)代碼單元表示,也就是一個(gè)char值。對于其他平面的字符(碼點(diǎn)范圍U+10000到U+10FFFF)可以使用兩個(gè)代碼單元表示,也就是兩個(gè)char值。
嚴(yán)格來說,char類型可以表示使用一個(gè)代碼單元表示的Unicode字符,char類型無法直接表示兩個(gè)代碼單元表示的字符。
怎么辦,對于需要兩個(gè)代碼單元表示的字符就不能使用了嗎?
不是的,我們可以把他們放在字符串類型中,字符串是由字符構(gòu)成的,它把U+D800到U+DBFF之間的代碼單元解讀為字符的第一個(gè)代碼單元,把U+DC00到U+DFFFF解讀為字符的第二個(gè)代碼單元,然后把兩個(gè)代碼單元解讀為一個(gè)字符。它把U+0000到U+FFFF之間除去替換區(qū)域(U+D800到U +DFFF)的代碼單元解讀為一個(gè)字符。
最后的建議,程序中最好不要使用char類型,除非你想處理代碼單元。像操作Unicode字符,可以使用Java中的String類型。
public static void main(String[] args) {// 字符串中放入需要兩個(gè)碼點(diǎn)表示的字符'𝕆'String str = "𝕆A";// 獲取索引為0的代碼單元,而不是字符char ch0 = str.charAt(0);char ch1 = str.charAt(1);char ch2 = str.charAt(2);System.out.println(ch0);System.out.println(ch1);System.out.println(ch2);}有些字符不能被正確的處理
總結(jié)
以上是生活随笔為你收集整理的Java char类型介绍的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Hulu热招|广告智能团队
- 下一篇: Java游戏项目之黄金矿工