在你查閱Java 5.0 JDK文檔時,當你發現Character類的每個方法幾乎都有相應的重載體時,千萬不要覺得奇怪。如果你細心的話,你肯定會發現,重載的方法差別幾乎都在參數類型上,某個方法的參數類型是char,而對應的重載方法的參數則為int。拿我們最重用的一個方法isUpperCase
來說,就有兩種定義:public static boolean isUpperCase(char ch)和public static boolean isUpperCase(int codePoint),前者是我們常用的,相信大家都不會感到奇怪。那么,后者用來干什么呢?既然都有了前一個方法,為什么還要有后面的這個重載方法呢?之所以這樣,是因為Java 5.0需要更好地支持Unicode編碼。
我們知道,任何事物都是在進化和發展中的,Unicode編碼也不例會。Java 5.0以前的JDK支持的是Unicode 3.0,而Java 5.0支持的則是Unicode 4.0。在Unicode 4.0中,定義了一些僅用16位無法表示的字符。既然無法用16位表示,而Java 5.0又支持這些字符,那么必然需要表示這些字符,顯然用char類型來表示肯定是不可能了,所以Java 5.0中用int類型來表示這些字符。既然表示字符的數據類型發生了變化,對應的方法自然也應該與時俱進了。
說完了原因,我們來了解幾個概念。首先說說代碼點(codepoint),它是一個數值,用來表示一個特定的字符,例如符號“派"(3.1415926)的代碼點就是0x3c0。另外一個概念是BMP(Basic Multilingual Plan ),指的是一個Java char類型(16位)所能表示的所有字符對應的代碼點集合,其范圍可想而知,從\u0000到\uffff;最后一個概念是增補字符,估計這個概念大家都知道表示什么了。對了,它用來表示那些16位無法表示的字符所對應的代碼點。增補字符的代碼點對應的數據類型雖然是int類型,但其范圍卻不是整個int類型的取值范圍,而只是其子集:0x10000到0x10ffff。可見增補字符只用到了int類型的后21位,而前11位則統一置為0,暫時不使用。
對于單個字符而言,其處理還是比較簡單的,如果我們需要用到unicode 4.0定義的那些額外字符,我們使用int類型來表示;如果我們不需要,我們直接使用char類型來表示就可以了。但現實往往是殘酷的,很多時候,我們可能希望將這些字符組合起來使用,更糟的是,可能這些組合中既包含16位能表示的,也不含16位表示不了的,我們該怎么辦呢?為了解決此問題,Java引入了兩類API,這兩類API都是基于代碼點的:用于各種?char 和基于代碼點的表示法之間轉換的方法和用于分析和映射代碼點的方法。這兩類方法都在Character類中定義,char和代碼點轉換的方法分別為toChars(int codePoint)和toEndPoint(char high, char low);檢測代碼點的方法則為Character 類中的isHighSurrogate 和isLowSurrogate 方法和charCount(int codePoint)方法。前兩個方法可以識別用于表示增補字符的char值;而最后一個方法可以確定是否需要將某個代碼點轉換為一個或兩個char。
為了體會這幾個方法的使用,我們可以看一下下面的示例:
package
?com.jiang.tiger.chap1;


public
?
class
?CharacterTester?
{
 ????
private
?
static
?
final
?
int
[]?code?
=
?
{
0x105600
,
0x105601
,?
0x105700
,?
0x10f255
,?
0x02f945
,?
0x036548
}
;
????
 ????
public
?
static
?String?toStr()?
{
????????String?str?
=
?
new
?String(code,?
0
,?code.length);
????????
return
?str;
????}
????
 ????
public
?
static
?
void
?printChar()?
{
????????
int
?length?
=
?code.length;
????????
char
[]?ch?
=
?
new
?
char
[
2
];
 ????????
for
(
int
?i?
=
?
0
;?i?
<
length;?i
++
?)?
{
????????????ch?
=
?Character.toChars(code[i]);
????????????System.out.printf(
"
code[%d]?=?0x%x
"
,?i,?code[i]);
????????????System.out.println();
????????????System.out.printf(
"
ch[0]?=?0x%x,?ch[1]?=?0x%x,?sum?=?0x%x
"
,(
int
)ch[
0
],?(
int
)ch[
1
],?(
int
)(ch[
0
]?
+
?ch[
1
]));
????????????System.out.println();
????????????System.out.printf(
"
back[%d]?=?0x%x
"
,?i,?Character.toCodePoint(ch[
0
],?ch[
1
]));
????????????System.out.println();????????
????????}
????????System.out.println(
"
ch[0]?is?highSurrogate:?
"
?
+
?Character.isHighSurrogate(ch[
0
]));
????????System.out.println(
"
ch[1]?is?LowSurrogate:?
"
?
+
?Character.isLowSurrogate(ch[
1
]));
????????System.out.println(
"
ch[1]?is??HighSurrogate:?
"
?
+
?Character.isHighSurrogate(ch[
1
]));
????????System.out.println(
"
0xcdff?is?LowSurrogate:?
"
?
+
?Character.isHighSurrogate((
char
)
0xcdff
));
????}
????
 ????
public
?
static
?
char
[]?toChar()?
{
????????
int
?length?
=
?code.length;
????????
char
[]?result?
=
?
new
?
char
[
2
?
*
?length];
????????
char
[]?ch?
=
?
new
?
char
[
2
];
 ????????
for
?(
int
?i?
=
?
0
;?i?
<
?length;?i
++
)?
{
????????????ch?
=
?Character.toChars(code[i]);
????????????result[
2
?
*
?i]?
=
?ch[
0
];
????????????result[
2
?
*
?i?
+
?
1
]?
=
?ch[
1
];
????????}
????????
return
?result;
????}
????
 ????
public
?
static
?
void
?main(String[]?args)?
{
????????String?str?
=
?CharacterTester.toStr();
????????System.out.println(
"
length?=?
"
?
+
?str.length());
????????
????????String?str2?
=
?str?
+
?
"
char
"
;
????????System.out.println(
"
length?=?
"
?
+
?str2.length());
????????
????????CharacterTester.printChar();
????????
????????
char
[]?ch?
=
?CharacterTester.toChar();
????????System.out.printf(
"
code[1]?=?0x%x
"
,?Character.codePointAt(ch,?
2
));
????????System.out.println();
????????
????}
????

}
上面示例的運行結果如下所示:
length?
=
?
12
length?
=
?
16
code
[
0
]
?
=
?0x105600
ch
[
0
]
?
=
?0xdbd5
,
?ch
[
1
]
?
=
?0xde00
,
?sum?
=
?0x1b9d5
back
[
0
]
?
=
?0x105600
code
[
1
]
?
=
?0x105601
ch
[
0
]
?
=
?0xdbd5
,
?ch
[
1
]
?
=
?0xde01
,
?sum?
=
?0x1b9d6
back
[
1
]
?
=
?0x105601
code
[
2
]
?
=
?0x105700
ch
[
0
]
?
=
?0xdbd5
,
?ch
[
1
]
?
=
?0xdf00
,
?sum?
=
?0x1bad5
back
[
2
]
?
=
?0x105700
code
[
3
]
?
=
?0x10f255
ch
[
0
]
?
=
?0xdbfc
,
?ch
[
1
]
?
=
?0xde55
,
?sum?
=
?0x1ba51
back
[
3
]
?
=
?0x10f255
code
[
4
]
?
=
?0x2f945
ch
[
0
]
?
=
?0xd87e
,
?ch
[
1
]
?
=
?0xdd45
,
?sum?
=
?0x1b5c3
back
[
4
]
?
=
?0x2f945
code
[
5
]
?
=
?0x36548
ch
[
0
]
?
=
?0xd899
,
?ch
[
1
]
?
=
?0xdd48
,
?sum?
=
?0x1b5e1
back
[
5
]
?
=
?0x36548
ch
[
0
]
?is?highSurrogate:?true
ch
[
1
]
?is?LowSurrogate:?true
ch
[
1
]
?is??HighSurrogate:?false
0xcdff?is?LowSurrogate:?false
code
[
1
]
?
=
?0x105601
Java對Unicode4.0的支持是新引入的一個功能,涉及的面很廣,作出修改的類也比較多,因此關于java對Unicode的支持的內容很多,本文只是拋磚引玉。如果對此感興趣的讀者,可以參考JDK,或是《Java 平臺中的增補字符》一文,該文鏈接為
http://gceclub.sun.com.cn/developer/technicalArticles/Intl/Supplementary/index_zh_CN.html
。
|