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

}
上面示例的運(yùn)行結(jié)果如下所示:
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對(duì)Unicode4.0的支持是新引入的一個(gè)功能,涉及的面很廣,作出修改的類(lèi)也比較多,因此關(guān)于java對(duì)Unicode的支持的內(nèi)容很多,本文只是拋磚引玉。如果對(duì)此感興趣的讀者,可以參考JDK,或是《Java 平臺(tái)中的增補(bǔ)字符》一文,該文鏈接為 http://gceclub.sun.com.cn/developer/technicalArticles/Intl/Supplementary/index_zh_CN.html 。
我們知道,任何事物都是在進(jìn)化和發(fā)展中的,Unicode編碼也不例會(huì)。Java 5.0以前的JDK支持的是Unicode 3.0,而Java 5.0支持的則是Unicode 4.0。在Unicode 4.0中,定義了一些僅用16位無(wú)法表示的字符。既然無(wú)法用16位表示,而Java 5.0又支持這些字符,那么必然需要表示這些字符,顯然用char類(lèi)型來(lái)表示肯定是不可能了,所以Java 5.0中用int類(lèi)型來(lái)表示這些字符。既然表示字符的數(shù)據(jù)類(lèi)型發(fā)生了變化,對(duì)應(yīng)的方法自然也應(yīng)該與時(shí)俱進(jìn)了。
說(shuō)完了原因,我們來(lái)了解幾個(gè)概念。首先說(shuō)說(shuō)代碼點(diǎn)(codepoint),它是一個(gè)數(shù)值,用來(lái)表示一個(gè)特定的字符,例如符號(hào)“派"(3.1415926)的代碼點(diǎn)就是0x3c0。另外一個(gè)概念是BMP(Basic Multilingual Plan ),指的是一個(gè)Java char類(lèi)型(16位)所能表示的所有字符對(duì)應(yīng)的代碼點(diǎn)集合,其范圍可想而知,從\u0000到\uffff;最后一個(gè)概念是增補(bǔ)字符,估計(jì)這個(gè)概念大家都知道表示什么了。對(duì)了,它用來(lái)表示那些16位無(wú)法表示的字符所對(duì)應(yīng)的代碼點(diǎn)。增補(bǔ)字符的代碼點(diǎn)對(duì)應(yīng)的數(shù)據(jù)類(lèi)型雖然是int類(lèi)型,但其范圍卻不是整個(gè)int類(lèi)型的取值范圍,而只是其子集:0x10000到0x10ffff。可見(jiàn)增補(bǔ)字符只用到了int類(lèi)型的后21位,而前11位則統(tǒng)一置為0,暫時(shí)不使用。
對(duì)于單個(gè)字符而言,其處理還是比較簡(jiǎn)單的,如果我們需要用到unicode 4.0定義的那些額外字符,我們使用int類(lèi)型來(lái)表示;如果我們不需要,我們直接使用char類(lèi)型來(lái)表示就可以了。但現(xiàn)實(shí)往往是殘酷的,很多時(shí)候,我們可能希望將這些字符組合起來(lái)使用,更糟的是,可能這些組合中既包含16位能表示的,也不含16位表示不了的,我們?cè)撛趺崔k呢?為了解決此問(wèn)題,Java引入了兩類(lèi)API,這兩類(lèi)API都是基于代碼點(diǎn)的:用于各種?char 和基于代碼點(diǎn)的表示法之間轉(zhuǎn)換的方法和用于分析和映射代碼點(diǎn)的方法。這兩類(lèi)方法都在Character類(lèi)中定義,char和代碼點(diǎn)轉(zhuǎn)換的方法分別為toChars(int codePoint)和toEndPoint(char high, char low);檢測(cè)代碼點(diǎn)的方法則為Character 類(lèi)中的isHighSurrogate 和isLowSurrogate 方法和charCount(int codePoint)方法。前兩個(gè)方法可以識(shí)別用于表示增補(bǔ)字符的char值;而最后一個(gè)方法可以確定是否需要將某個(gè)代碼點(diǎn)轉(zhuǎn)換為一個(gè)或兩個(gè)char。
為了體會(huì)這幾個(gè)方法的使用,我們可以看一下下面的示例:









































































上面示例的運(yùn)行結(jié)果如下所示:

























Java對(duì)Unicode4.0的支持是新引入的一個(gè)功能,涉及的面很廣,作出修改的類(lèi)也比較多,因此關(guān)于java對(duì)Unicode的支持的內(nèi)容很多,本文只是拋磚引玉。如果對(duì)此感興趣的讀者,可以參考JDK,或是《Java 平臺(tái)中的增補(bǔ)字符》一文,該文鏈接為 http://gceclub.sun.com.cn/developer/technicalArticles/Intl/Supplementary/index_zh_CN.html 。