Unicode字符集
Unicode,是計(jì)算機(jī)科學(xué)領(lǐng)域里的一項(xiàng)業(yè)界標(biāo)準(zhǔn)。為每種語言中的每個(gè)字符設(shè)定了統(tǒng)一并且唯一的整數(shù)值,把這個(gè)數(shù)值稱為碼點(diǎn)(Code Point)。
但是它并不規(guī)定計(jì)算機(jī)如何存儲(chǔ)和傳輸這個(gè)數(shù)值(以多少個(gè)字節(jié)存儲(chǔ),是定長(zhǎng)還是變長(zhǎng),Unicode沒有字節(jié)長(zhǎng)度的概念)。
Unicode 定義了一個(gè)碼點(diǎn)空間包含1,114,112個(gè)碼點(diǎn),范圍從0到0x10FFFF,也就是說,它僅僅是一個(gè)字符映射集。其中 0x0000 ~ 0xFFFF 的字符表示常用字符集,稱 BMP字符,0x10000 ~ 0x10FFFF 字符叫增補(bǔ)字符。
Unicode 目前規(guī)劃的總空間是17個(gè)平面(平面0至16),0x0000 至 0x10FFFF,每個(gè)平面有 65536 個(gè)碼點(diǎn)。
例如,"AB中國"這個(gè)字符串,對(duì)應(yīng)的 Unicode 編碼為:
A -> \u0041
B -> \u0042
中 -> \u0049
國 -> \u56FD
Unicode的實(shí)現(xiàn)
同一 Unicode 值可以被編碼成不同的二進(jìn)制表示,以便在存儲(chǔ)和網(wǎng)絡(luò)上傳輸。Unicode的實(shí)現(xiàn):UTF-8、UTF-16、UTF-32、UCS-2等。
UTF-8, Unicode Transformation Format – 8-bit
- 使用 1 ~ 4 個(gè)字節(jié)變長(zhǎng)編碼表示「1,112,064」個(gè) Unicode 碼點(diǎn)
- 兼容 ASCII
- 碼點(diǎn)數(shù)值越小,使用的字節(jié)數(shù)越少,出現(xiàn)的頻率越高
UTF-16
- 使用 1 ~ 2 個(gè) 16bit 變長(zhǎng)編碼表示「1,112,064」個(gè) Unicode 碼點(diǎn)
- 它擴(kuò)展于固定16bit長(zhǎng)度的UCS-2
UTF-32
- 4 字節(jié)定長(zhǎng)編碼
- 其高位均為0,空間浪費(fèi)比較嚴(yán)重,因此應(yīng)用很少
Java 使用何種編碼
Java char 占 2 個(gè)字節(jié),使用 UTF-16BE 表示一個(gè)字符。由于它只使用 2 個(gè)字節(jié),所以 char 只用能表示部分 UTF-16 編碼,即 0x0000 ~ 0xFFFF。對(duì)于 4 字節(jié)的 UTF-16,需要使用 2 個(gè) char。
String 始終是按 UTF-16BE 處理字符的,對(duì) BMP 字符,使用一個(gè) char,兩個(gè)字節(jié);對(duì)于增補(bǔ)字符,使用兩個(gè) char,四個(gè)字節(jié)。以上是由 Java language spec 規(guī)定的。
Java 源文件默認(rèn)采用平臺(tái)編碼存儲(chǔ),Linux/Unix 是 UTF-8,Window 采用 GBK。一般常用的 IDE 如 Intellij IDEA 和 Eclipse 都能提供多種編碼。編譯器 javac 讀取 Java 源文件時(shí),如果不顯示指定 -encoding,則默認(rèn)以 Charset.defaultCharset() 讀取,如果與源文件的編碼不同,則會(huì)報(bào)錯(cuò)。
javac -encoding gbk/utf-8 僅告訴編譯器以何種編碼讀取 Java 源文件,然后編譯器在編譯時(shí)就用指定的編碼把源文件的字符串轉(zhuǎn)化為UTF-8字符串。
不管 Java 源文件是什么編碼,Java class 字節(jié)碼文件中字符串字面量始終是 UTF-8 編碼,這是由 JVM spec 規(guī)定。
UTF-8 和 GBK2312 編碼的 Java 源文件,分別編譯成 class 文件,兩者相同。
System.out、PrintStream 將會(huì)在輸出之前,把字符串從 UTF-16 轉(zhuǎn)換成默認(rèn)系統(tǒng)編碼(JVM 從操作系統(tǒng)讀?。?。
Java 中把 String 轉(zhuǎn)換成字節(jié)碼,默認(rèn)使用平臺(tái)默認(rèn)的編碼??纯?getBytes 的注釋。
/**
* Encodes this {@code String} into a sequence of bytes using the
* platform's default charset, storing the result into a new byte array.
*
* <p> The behavior of this method when this string cannot be encoded in
* the default charset is unspecified. The {@link
* java.nio.charset.CharsetEncoder} class should be used when more control
* over the encoding process is required.
*
* @return The resultant byte array
*
* @since JDK1.1
*/
public byte[] getBytes() {
return StringCoding.encode(value, 0, value.length);
}