1. 程式人生 > >Java中的代碼點和代碼單元(轉)

Java中的代碼點和代碼單元(轉)

swing enter 錯誤 字體 消息 關系 小文本 開發人員 界面

文章來源:http://blog.csdn.net/weizhaozhe/article/details/3909079

這篇文章講的很細,但是對於初學者也很難理解,在後面的筆記中,我會陳述自己的簡單理解。

摘要

本文介紹 Java 平臺支持增補字符的方式。增補字符是 Unicode 標準中代碼點超出 U+FFFF 的字符,因此它們無法在 Java 編程語言中描述為單個的 16 位實體(例如char數據類型)。這些字符一般極少用,但是,有些會在諸如中文或日文人名中用到,因此,在東亞國家,政府應用程序通常會要求支持這些字符。

Java 平臺目前正在改進,以便支持對增補字符的處理,這種改進對現有的應用程序影響微乎其微。新的低層 API 在需要時能夠使用單個的字符運行。不過,大多數文本處理 API 均使用字符序列,例如String類或字符數組。現在,這些均解釋為 UTF-16 序列,而且,這些 API 實現已轉變為正確地處理增補字符。這些改進已融入 Java 2 平臺 5.0 版,標準版 (J2SE)。

除詳細解釋這些改進之外,本文同時為應用程序開發人員確定和實現必要的更改提供指導,以支持整個 Unicode 字符集的使用。

背景

Unicode 最初設計是作為一種固定寬度的 16 位字符編碼。在 Java 編程語言中,基本數據類型char初衷是通過提供一種簡單的、能夠包含任何字符的數據類型來充分利用這種設計的優點。不過,現在看來,16 位編碼的所有 65,536 個字符並不能完全表示全世界所有正在使用或曾經使用的字符。於是,Unicode 標準已擴展到包含多達 1,112,064 個字符。那些超出原來的 16 位限制的字符被稱作增補字符。Unicode 標準 2.0 版是第一個包含啟用增補字符設計的版本,但是,直到 3.1 版才收入第一批增補字符集。由於 J2SE 的 5.0 版必須支持 Unicode 標準 4.0 版,因此它必須支持增補字符。

對增補字符的支持也可能會成為東亞市場的一個普遍商業要求。政府應用程序會需要這些增補字符,以正確表示一些包含罕見中文字符的姓名。出版應用程序可能會需要這些增補字符,以表示所有的古代字符和變體字符。中國政府要求支持 GB18030(一種對整個 Unicode 字符集進行編碼的字符編碼標準),因此,如果是 Unicode 3.1 版或更新版本,則將包括增補字符。臺灣標準 CNS-11643 包含的許多字符在 Unicode 3.1 中列為增補字符。香港政府定義了一種針對粵語的字符集,其中的一些字符是 Unicode 中的增補字符。最後,日本的一些供應商正計劃利用增補字符空間中大量的專用空間收入 50,000 多個日文漢字字符變體,以便從其專有系統遷移至基於 Java 平臺的解決方案。

因此,Java 平臺不僅需要支持增補字符,而且必須使應用程序能夠方便地做到這一點。由於增補字符打破了 Java 編程語言的基礎設計構想,而且可能要求對編程模型進行根本性的修改,因此,Java Community Process 召集了一個專家組,以期找到一個適當的解決方案。該小組被稱為 JSR-204 專家組,使用Unicode 增補字符支持的 Java 技術規範請求的編號。從技術上來說,該專家組的決定僅適用於 J2SE 平臺,但是由於 Java 2 平臺企業版 (J2EE) 處於 J2SE 平臺的最上層,因此它可以直接受益,我們期望 Java 2 平臺袖珍版 (J2ME) 的配置也采用相同的設計方法。

不過,在了解 JSR-204 專家組確定的解決方案之前,我們需要先理解一些術語。

代碼點、字符編碼方案、UTF-16:這些是指什麽?

不幸的是,引入增補字符使字符模型變得更加復雜了。在過去,我們可以簡單地說“字符”,在一個基於 Unicode 的環境(例如 Java 平臺)中,假定字符有 16 位,而現在我們需要更多的術語。我們會盡量介紹得相對簡單一些 — 如需了解所有詳細的討論信息,您可以閱讀Unicode 標準第 2 章或 Unicode 技術報告 17“字符編碼模型”。Unicode 專業人士可略過所有介紹直接參閱本部分中的最後定義。

字符是抽象的最小文本單位。它沒有固定的形狀(可能是一個字形),而且沒有值。“A”是一個字符,“€”(德國、法國和許多其他歐洲國家通用貨幣的標誌)也是一個字符。

字符集是字符的集合。例如,漢字字符是中國人最先發明的字符,在中文、日文、韓文和越南文的書寫中使用。

編碼字符集是一個字符集,它為每一個字符分配一個唯一數字。Unicode 標準的核心是一個編碼字符集,字母“A”的編碼為 004116 和字符“€”的編碼為20AC16.Unicode 標準始終使用十六進制數字,而且在書寫時在前面加上前綴“U+”,所以“A”的編碼書寫為“U+0041”。

代碼點是指可用於編碼字符集的數字。編碼字符集定義一個有效的代碼點範圍,但是並不一定將字符分配給所有這些代碼點。有效的 Unicode 代碼點範圍是 U+0000 至 U+10FFFF.Unicode 4.0 將字符分配給一百多萬個代碼點中的 96,382 代碼點。

增補字符是代碼點在 U+10000 至 U+10FFFF 範圍之間的字符,也就是那些使用原始的 Unicode 的 16 位設計無法表示的字符。從 U+0000 至 U+FFFF 之間的字符集有時候被稱為基本多語言面 (BMP)。因此,每一個 Unicode 字符要麽屬於 BMP,要麽屬於增補字符。

字符編碼方案是從一個或多個編碼字符集到一個或多個固定寬度代碼單元序列的映射。最常用的代碼單元是字節,但是 16 位或 32 位整數也可用於內部處理。UTF-32、UTF-16 和 UTF-8 是 Unicode 標準的編碼字符集的字符編碼方案。

UTF-32 即將每一個 Unicode 代碼點表示為相同值的 32 位整數。很明顯,它是內部處理最方便的表達方式,但是,如果作為一般字符串表達方式,則要消耗更多的內存。

UTF-16 使用一個或兩個未分配的 16 位代碼單元的序列對 Unicode 代碼點進行編碼。值 U+0000 至 U+FFFF 編碼為一個相同值的 16 位單元。增補字符編碼為兩個代碼單元,第一個單元來自於高代理範圍(U+D800 至 U+DBFF),第二個單元來自於低代理範圍(U+DC00 至 U+DFFF)。這在概念上可能看起來類似於多字節編碼,但是其中有一個重要區別:值 U+D800 至 U+DFFF 保留用於 UTF-16;沒有這些值分配字符作為代碼點。這意味著,對於一個字符串中的每個單獨的代碼單元,軟件可以識別是否該代碼單元表示某個單單元字符,或者是否該代碼單元是某個雙單元字符的第一個或第二單元。這相當於某些傳統的多字節字符編碼來說是一個顯著的改進,在傳統的多字節字符編碼中,字節值 0x41 既可能表示字母“A”,也可能是一個雙字節字符的第二個字節。

UTF-8 使用一至四個字節的序列對編碼 Unicode 代碼點進行編碼。U+0000 至 U+007F 使用一個字節編碼,U+0080 至 U+07FF 使用兩個字節,U+0800 至 U+FFFF 使用三個字節,而 U+10000 至 U+10FFFF 使用四個字節。UTF-8 設計原理為:字節值 0x00 至 0x7F 始終表示代碼點 U+0000 至 U+007F(Basic Latin 字符子集,它對應 ASCII 字符集)。這些字節值永遠不會表示其他代碼點,這一特性使 UTF-8 可以很方便地在軟件中將特殊的含義賦予某些 ASCII 字符。

下表所示為幾個字符不同表達方式的比較:

Unicode U+0041 U+00DF U+6771 U+10400
表示字形
UTF-32 碼單
00000041
000000DF
00006771
00010400
UTF-16 碼單
0041
00DF
6771
D801 DC00
UTF-8 碼單
41
C3 9F
E6 9D B1
F0 90 90 80

另外,本文在許多地方使用術語字符序列或char序列概括 Java 2 平臺識別的所有字符序列的容器:char[], java.lang.CharSequence的實現(例如String類),和java.text.CharacterIterator的實現。

這麽多術語。它們與在 Java 平臺中支持增補字符有什麽關系呢?

Java 平臺中增補字符的設計方法

JSR-204 專家組必須作出的主要決定是如何在 Java API 中表示增補字符,包括單個字符和所有形式的字符序列。專家組考慮並排除了多種方法:

重新定義基本類型char,使其具有 32 位,這樣也會使所有形式的char序列成為 UTF-32 序列。
在現有的 16 位類型char的基礎上,為字符引入一種新的 32 位基本類型(例如,char32)。所有形式的 Char 序列均基於 UTF-16.
在現有的 16 位類型char的基礎上,為字符引入一種新的 32 位基本類型(例如,char32)。String和StringBuffer接受並行 API,並將它們解釋為 UTF-16 序列或 UTF-32 序列;其他char序列繼續基於 UTF-16.
使用int表示增補的代碼點。String和StringBuffer接受並行 API,並將它們解釋為 UTF-16 序列或 UTF-32 序列;其他char序列繼續基於 UTF-16.
使用代理char對,表示增補代碼點。所有形式的char序列基於 UTF-16.
引入一種封裝字符的類。String和StringBuffer接受新的 API,並將它們解釋為此類字符的序列。
使用一個CharSequence實例和一個索引的組合表示代碼點。

在這些方法中,一些在早期就被排除了。例如,重新定義基本類型char,使其具有 32 位,這對於全新的平臺可能會非常有吸引力,但是,對於 J2SE 來說,它會與現有的 Java 虛擬機1、序列化和其他接口不兼容,更不用說基於 UTF-32 的字符串要使用兩倍於基於 UTF-16 的字符串的內存了。添加一種新類型的char32可能會簡單一些,但是仍然會出現虛擬機和序列化方面的問題。而且,語言更改通常需要比 API 更改有更長的提前期,因此,前面兩種方法會對增補字符支持帶來無法接受的延遲。為了在余下的方法中篩選出最優方案,實現小組使用四種不同的方法,在大量進行低層字符處理的代碼(java.util.regex包)中實現了對增補字符支持,並對這四種方法的難易程度和運行表現進行了比較。

最終,專家組確定了一種分層的方法:

使用基本類型int在低層 API 中表示代碼點,例如Character類的靜態方法。
將所有形式的char序列均解釋為 UTF-16 序列,並促進其在更高層級 API 中的使用。
提供 API,以方便在各種char和基於代碼點的表示法之間的轉換。

在需要時,此方法既能夠提供一種概念簡明且高效的單個字符表示法,又能夠充分利用通過改進可支持增補字符的現有 API.同時,還能夠促進字符序列在單個字符上的應用,這一點一般對於國際化的軟件很有好處。

在這種方法中,一個char表示一個 UTF-16 代碼單元,這樣對於表示代碼點有時並不夠用。您會註意到,J2SE 技術規範現在使用術語代碼點和 UTF-16 代碼單元(表示法是相關的)以及通用術語字符(表示法與該討論沒有關系)。API 通常使用名稱codePoint描述表示代碼點的類型int的變量,而 UTF-16 代碼單元的類型當然為char.我們將在下面兩部分中了解到 J2SE 平臺的實質變化 — 其中一部分介紹單個代碼點的低層 API,另一部分介紹采用字符序列的高層接口。

開放的增補字符:基於代碼點的 API

新增的低層 API 分為兩大類:用於各種char和基於代碼點的表示法之間轉換的方法和用於分析和映射代碼點的方法。

最基本的轉換方法是Character.toCodePoint(char high, char low)(用於將兩個 UTF-16 代碼單元轉換為一個代碼點)和Character.toChars(int codePoint)(用於將指定的代碼點轉換為一個或兩個 UTF-16 代碼單元,然後封裝到一個char[]內。不過,由於大多數情況下文本以字符序列的形式出現,因此,另外提供codePointAt和codePointBefore方法,用於將代碼點從各種字符序列表示法中提取出來:Character.codePointAt(char[] a, int index)和String.codePointBefore(int index)是兩種典型的例子。在將代碼點插入字符序列時,大多數情況下均有一些針對StringBuffer和StringBuilder類的appendCodePoint(int codePoint)方法,以及一個用於提取表示代碼點的int[]的String構建器。

幾種用於分析代碼單元和代碼點的方法有助於轉換過程:Character 類中的isHighSurrogate和isLowSurrogate方法可以識別用於表示增補字符的char值;charCount(int codePoint)方法可以確定是否需要將某個代碼點轉換為一個或兩個char.但是,大多數基於代碼點的方法均能夠對所有 Unicode 字符實現基於char的舊方法對 BMP 字符所實現的功能。以下是一些典型例子:

Character.isLetter(int codePoint)可根據 Unicode 標準識別字母。
Character.isJavaIdentifierStart(int codePoint)可根據 Java 語言規範確定代碼點是否可以啟動標識符。
Character.UnicodeBlock.of(int codePoint)可搜索代碼點所屬的 Unicode 字符子集。
Character.toUpperCase(int codePoint)可將給定的代碼點轉換為其大寫等值字符。盡管此方法能夠支持增補字符,但是它仍然不能解決根本的問題,即在某些情況下,逐個字符的轉換無法正確完成。例如,德文字符“"?"”應該轉換為“SS”,這需要使用String.toUpperCase方法。

註意大多數接受代碼點的方法並不檢查給定的int值是否處於有效的 Unicode 代碼點範圍之內(如上所述,只有 0x0 至 0x10FFFF 之間的範圍是有效的)。在大多數情況下,該值是以確保其有效的方法產生的,在這些低層 API 中反復檢查其有效性可能會對系統性能造成負面的影響。在無法確保有效性的情況下,應用程序必須使用Character.isValidCodePoint方法確保代碼點有效。大多數方法對於無效的代碼點采取的行為沒有特別加以指定,不同的實現可能會有所不同。

API 包含許多簡便的方法,這些方法可使用其他低層的 API 實現,但是專家組覺得,這些方法很常用,將它們添加到 J2SE 平臺上很有意義。不過,專家組也排除了一些建議的簡便方法,這給我們提供了一次展示自己實現此類方法能力的機會。例如,專家組經過討論,排除了一種針對String類的新構建器(該構建器可以創建一個保持單個代碼點的String)。以下是使應用程序使用現有的 API 提供功能的一種簡便方法:

/**
* 創建僅含有指定代碼點的新 String.
*/
String newString(int codePoint) {
return new String(Character.toChars(codePoint));
}

您會註意到,在這個簡單的實現中,toChars方法始終創建一個中間數列,該數列僅使用一次即立即丟棄。如果該方法在您的性能評估中出現,您可能會希望將其優化為針對最為普通的情況,即該代碼點為 BMP 字符:

/**
* 創建僅含有指定代碼點的新 String.
* 針對 BMP 字符優化的版本。
*/
String newString(int codePoint) {
if (Character.charCount(codePoint) == 1) {
return String.valueOf((char) codePoint);
}
else {
return new String(Character.toChars(codePoint));
}
}

或者,如果您需要創建許多個這樣的 string,則可能希望編寫一個重復使用toChars方法所使用的數列的通用版本:

/**
* 創建每一個均含有一個指定
* 代碼點的新 String.
* 針對 BMP 字符優化的版本。
*/
String[] newStrings(int[] codePoints) {
String[] result = new String[codePoints.length];
char[] codeUnits = new char[2];
for (int i = 0; i < codePoints.length; i++) {
int count = Character.toChars(codePoints[i], codeUnits, 0);
result[i] = new String(codeUnits, 0, count);
}
return result;
}

不過,最終您可能會發現,您需要的是一個完全不同的解決方案。新的構建器String(int codePoint)實際上建議作為String.valueOf(char)的一個基於代碼點的備選方案。在很多情況下,此方法用於消息生成的環境,例如:

System.out.println("Character " + String.valueOf(char) + " is invalid.");

新的格式化 API支持增補文字,提供一種更加簡單的備選方案:

System.out.printf("Character %c is invalid.%n", codePoint);

使用此高層 API 不僅簡捷,而它有很多特殊的優點:它可以避免串聯(串聯會使消息很難本地化),並將需要移進資源包 (resource bundle) 的字符串數量從兩個減少到一個。

增補字符透視:功能增強

在支持使用增補字符的 Java 2 平臺中的大部分更改沒有反映到新的 API 內。一般預期是,處理字符序列的所有接口將以適合其功能的方式處理增補字符。本部分著重講述為達到此預期所作一些功能增強。

Java 編程語言中的標識符

Java 語言規範指出所有 Unicode 字母和數字均可用於標識符。許多增補字符是字母或數字,因此 Java 語言規範已經參照新的基於代碼點的方法進行更新,以在標識符內定義合法字符。為使用這些新方法,需要檢測標識符的 javac 編譯器和其他工具都進行了修訂。

庫內的增補字符支持

許多 J2SE 庫已經過增強,可以通過現有接口支持增補字符。以下是一些例子:

字符串大小寫轉換功能已更新,可以處理增補字符,也可以實現 Unicode 標準中規定的特殊大小寫規則。
java.util.regex包已更新,這樣模式字符串和目標字符串均可以包含增補字符並將其作為完整單元處理。
現在,在java.text包內進行整理處理時,會將增補字符看作完整單元。
java.text.Bidi類已更新,可以處理增補字符和 Unicode 4.0 中新增的其他字符。請註意,Cypriot Syllabary 字符子集內的增補字符具有從右至左的方向性。
Java 2D API 內的字體渲染和打印技術已經過增強,可以正確渲染和測量包含增補字符的字符串。
Swing 文本組件實現已更新,可以處理包含增補字符的文本。

字符轉換

只有很少的字符編碼可以表示增補字符。如果是基於 Unicode 的編碼(如 UTF-8 和 UTF-16LE),則舊版的 J2RE 內的字符轉換器已經按照正確處理增補字符的方式實現轉換。對於 J2RE 5.0,可以表示增補字符的其他編碼的轉換器已更新:GB18030、x-EUC-TW(現在實現所有 CNS 11643 層面)和 Big5-HKSCS(現在實現 HKSCS-2001)。

在源文件內表示增補字符

在 Java 編程語言源文件中,如果使用可以直接表示增補字符的字符編碼,則使用增補字符最為方便。UTF-8 是最佳的選擇。在所使用的字符編碼無法直接表示字符的情況下,Java 編程語言提供一種 Unicode 轉義符語法。此語法沒有經過增強,無法直接表示增補字符。而是使用兩個連續的 Unicode 轉義符將其表示為 UTF-16 字符表示法中的兩個編碼單元。例如,字符 U+20000 寫作“/uD840/uDC00”。您也許不願意探究這些轉義序列的含義;最好是寫入支持所需增補字符的編碼,然後使用一種工具(如 native2ascii)將其轉換為轉義序列。

遺憾的是,由於其編碼問題,屬性文件仍局限於 ISO 8859-1(除非您的應用程序使用新的 XML 格式)。這意味著您始終必須對增補字符使用轉義序列,而且可能要使用不同的編碼進行編寫,然後使用諸如 native2ascii 的工具進行轉換。

經修訂的 UTF-8

Java 平臺對經修訂的 UTF-8 已經很熟悉,但是,問題是應用程序開發人員在可能包含增補字符的文本和 UTF-8 之間進行轉換時需要更加留神。需要特別註意的是,某些 J2SE 接口使用的編碼與 UTF-8 相似但與其並不兼容。以前,此編碼有時被稱為“Java modified UTF-8”(經 Java 修訂的 UTF-8)或(錯誤地)直接稱為“UTF-8”。對於 J2SE 5.0,其說明文檔正在更新,此編碼將統稱為“modified UTF-8”(經修訂的 UTF-8)。

經修訂的 UTF-8 和標準 UTF-8 之間之所以不兼容,其原因有兩點。其一,經修訂的 UTF-8 將字符 U+0000 表示為雙字節序列 0xC0 0x80,而標準 UTF-8 使用單字節值 0x0.其二,經修訂的 UTF-8 通過對其 UTF-16 表示法的兩個代理代碼單元單獨進行編碼表示增補字符。每個代理代碼單元由三個字節來表示,共有六個字節。而標準 UTF-8 使用單個四字節序列表示整個字符。

Java 虛擬機及其附帶的接口(如 Java 本機接口、多種工具接口或 Java 類文件)在java.io.DataInput和DataOutput接口和類中使用經修訂的 UTF-8 實現或使用這些接口和類,並進行序列化。Java 本機接口提供與經修訂的 UTF-8 之間進行轉換的例程。而標準 UTF-8 由String類、java.io.InputStreamReader和OutputStreamWriter類、java.nio.charset設施 (facility) 以及許多其上層的 API 提供支持。

由於經修訂的 UTF-8 與標準的 UTF-8 不兼容,因此切勿同時使用這兩種版本的編碼。經修訂的 UTF-8 只能與上述的 Java 接口配合使用。在任何其他情況下,尤其對於可能來自非基於 Java 平臺的軟件的或可能通過其編譯的數據流,必須使用標準的 UTF-8.需要使用標準的 UTF-8 時,則不能使用 Java 本機接口例程與經修訂的 UTF-8 進行轉換。

在應用程序內支持增補字符

現在,對大多數讀者來說最為重要的問題是:必須對應用程序進行哪些更改才能支持增補字符?

答案取決於在應用程序中進行哪種類型的文本處理和使用哪些 Java 平臺 API.對於僅以各種形式char序列([char[]、java.lang.CharSequence實現、java.text.CharacterIterator實現)處理文本和僅使用接受和退回序列(如char序列)的 Java API 的應用程序,可能根本不需要進行任何更改。Java 平臺 API 的實現應該能夠處理增補字符。

對於本身解釋單個字符、將單個字符傳送給 Java 平臺 API 或調用能夠返回單個字符的方法的應用程序,則需要考慮這些字符的有效值。在很多情況下,往往不要求支持增補字符。例如,如果某應用程序搜索char序列中的 HTML 標記,並逐一檢查每個char,它會知道這些標記僅使用 Basic Latin 字符子集中的字符。如果所搜索的文本含有增補字符,則這些字符不會與標記字符混淆,因為 UTF-16 使用代碼單元表示增補字符,而代碼單元的值不會用於 BMP 字符。

只有在某應用程序本身解釋單個字符、將單個字符傳送給 Java 平臺 API 或調用能夠返回單個字符的方法且這些字符可能為增補字符時,才必須更改該應用程序。在提供使用char序列的並行 API 時,最好轉而使用此類 API.在其他情況下,有必要使用新的 API 在char和基於代碼點的表示法之間進行轉換,並調用基於代碼點的 API.當然,如果您發現在 J2SE 5.0 中有更新、更方便的 API,使您能夠支持增補字符並同時簡化代碼(如上格式化範例中所述),則沒有必要這樣做。

您可能會猶豫,是將所有文本轉換為代碼點表示法(即int[])然後在該表示法中處理,還是在大多數情況下仍采用char序列,僅在需要時轉換為代碼點,兩者之間孰優孰劣很難確定。當然,總體來說,Java 平臺 API 相對於char序列肯定具有一定的優勢,而且采用 Java 平臺 API 可以節省內存空間。

對於需要與 UTF-8 之間進行轉換的應用程序,還需要認真考慮是需要標準的 UTF-8 還是經修訂的 UTF-8,並針對每種 UTF-8 采用適當的 Java 平臺。“經修訂的 UTF-8”部分介紹進行正確選擇所需的信息。

使用增補字符測試應用程序

經過前面部分的介紹後,無論您是否需要修訂應用程序,測試應用程序是否運行正常始終是一種正確的做法。對於不含有圖形用戶界面的應用程序,有關“在源文件內表示增補字符” 的信息有助於設計測試用例。以下是有關使用圖形用戶界面進行測試的補充信息。

對於文本輸入,Java 2 SDK提供用於接受“/Uxxxxxx”格式字符串的代碼點輸入方法,這裏大寫的“U”表示轉義序列包含六個十六進制數字,因此允許使用增補字符。小寫的“u”表示轉義序列“/uxxxx”的原始格式。您可以在 J2SDK 目錄 demo/jfc/CodePointIM 內找到此輸入方法及其說明文檔。

對於字體渲染,您需要至少能夠渲染一些增補字符的字體。其中一種此類字體為 James Kass 的Code2001字體,它提供手寫體字形(如 Deseret 和 Old Italic)。利用 Java 2D 庫中提供新功能,您只需將該字體安裝到 J2RE 的 lib/fonts/fallback 目錄內即可,然後它可自動添加至在 2D 和 XAWT 渲染時使用的所有邏輯字體 — 無需編輯字體配置文件。

至此,您就可以確認,您的應用程序能夠完全支持增補字符了!

結論

對增補字符的支持已經引入 Java 平臺,大部分應用程序無需更改代碼即可處理這些字符。解釋單個字符的應用程序可以在Character類和多種CharSequence子類中使用基於代碼點的新 API.

以下是Unicode和UTF-8之間的轉換關系表:

U-00000000 - U-0000007F: 0xxxxxxx
U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

Byte 數組轉整數:

static int bytes2int(byte[] b)
{
int mask=0xff;
int temp=0;
int res=0;
for(int i=0;i<4;i++){
res<<=8;
temp=b[i]&mask;
res|=temp;
}
return res;
}

整數轉byte數組:

static byte[] int2bytes(int num)
{
byte[] b=new byte[4];
int mask=0xff;
for(int i=0;i<4;i++){
b[i]=(byte)(num>>>(24-i*8));
}
return b;
}

Java中的代碼點和代碼單元(轉)