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