Java 5.0对Unicode码的支持
在你查阅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 。
我们知道,任何事物都是在进化和发展中的,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。
为了体会这几个方法的使用,我们可以看一下下面的示例:
上面示例的运行结果如下所示:
Java对Unicode4.0的支持是新引入的一个功能,涉及的面很广,作出修改的类也比较多,因此关于java对Unicode的支持的内容很多,本文只是抛砖引玉。如果对此感兴趣的读者,可以参考JDK,或是《Java 平台中的增补字符》一文,该文链接为 http://gceclub.sun.com.cn/developer/technicalArticles/Intl/Supplementary/index_zh_CN.html 。