谜题14至17,讲的都是用16进制代码表示unicode字符导致的问题。
知识点:
Java对在字符串字面常量中的Unicode转义字符(16进制表示)没有提供任何特殊处理。
编译器在将程序解析成各种符号之前,先将Unicode转义字符转换成为它们所表示的字符[JLS 3.2]。
普通的转义字符序列和八进制转义字符都比Unicode 转义字符要好得多,因为与Unicode 转义字符不同,
转义字符序列是在程序被解析为各种符号之后被处理的。
问题:
下面的程序会打印什么?
public class EscapeRout{
public static void main(String[] args){
// \u0022 是双引号的Unicode 转义字符
System.out.println("a\u0022.length() +\u0022b".length());
}
}
// 期望结果:26或16
// 实际结果:2
结果是不是出乎大家的意料呢?的确如此。
产生这个结果的原因:
对该程序的一种很肤浅的分析会认为它应该打印出26,因为在由两个双引号 "a\u0022.length()+\u0022b"标识的字符串之间总共有 26个字符。 稍微深入一点的分析会认为该程序应该打印16,因为两个Unicode 转义字符每 一个在源文件中都需要用6个字符来表示,但是它们只表示字符串中的一个字 符。因此这个字符串应该比它的外表看其来要短10 个字符。 如果你运行这个程 序,就会发现事情远不是这么回事。它打印的既不是 26也不是 16,而是 2。 理解这个谜题的关键是要知道:Java 对在字符串字面常量中的Unicode 转义字 符没有提供任何特殊处理。编译器在将程序解析成各种符号之前,先将Unicode 转义字符转换成为它们所表示的字符[JLS 3.2]。因此,程序中的第一个Unicode 转义字符将作为一个单字符字符串字面常量("a")的结束引号,而第二个 Unicode 转义字符将作为另一个单字符字符串字面常量("b")的开始引号。程 序打印的是表达式"a".length()+"b".length(),即 2。 如果该程序的作者确实希望得到这种行为,那么下面的语句将要清楚得多: System.out.println("a".length()+"b".length()); |
解决方法:
你可以使用“普通的转义字符序列(\x)”和“八进制转义序列\000”来替换16进制表示的unicode(\uXXXX)转义字符。
从而来明确表达你的意图。
1、System.out.println("a".length()+"b".length()); // 2
2、System.out.println("a\".length()+\"b".length()); // 16
总结:
1、不要使用Unicode 转义字符来表示ASCII字符;
2、在字符串和字符字面常量中要优先选择的是转义字符序列(普通转义字符或八进制转义字符),
而不是Unicode 转义字符;
3、ASCII是字符集的最小公共特性集,它只有 128(2^7)个字符,但是Unicode 有超65,000 (2^16-1)个字符。
一个Unicode 转义字符可以被用来在只使用 ASCII字符的程序中插入一个Unicode字符。
一个Unicode转义字符精确地等价于它所表示的字符。Unicode 转义字符被设计为用于
在程序员需要插入一个不能用源文件字符集表示的字符的情况。
实际上,你可以通过使用被称为八进制转义字符的特殊类型的转义字符序列,将 任何 ASCII字符置于一个字符串字面常量或一个字符字面常量中,但是最好是尽 可能地使用普通的转义字符序列。 普通的转义字符序列和八进制转义字符都比Unicode 转义字符要好得多,因为与 Unicode 转义字符不同,转义字符序列是在程序被解析为各种符号之后被处理 的。 ASCII是字符集的最小公共特性集,它只有 128个字符,但是Unicode 有超过 65,000 个字符。一个Unicode 转义字符可以被用来在只使用 ASCII字符的程序 中插入一个Unicode字符。一个Unicode转义字符精确地等价于它所表示的字符。 Unicode 转义字符被设计为用于在程序员需要插入一个不能用源文件字符集表 示的字符的情况。它们主要用于将非 ASCII字符置于标识符、字符串字面常量、 字符字面常量以及注释中。偶尔地,Unicode 转义字符也被用来在看起来颇为相 似的数个字符中明确地标识其中的某一个,从而增加程序的清晰度。
总之,在字符串和字符字面常量中要优先选择的是转义字符序列,而不是 Unicode 转义字符。Unicode 转义字符可能会因为它们在编译序列中被处理得过 早而引起混乱。不要使用Unicode 转义字符来表示ASCII字符。在字符串和字符 字面常量中,应该使用转义字符序列;对于除这些字面常量之外的情况,应该直 接将 ASCII字符插入到源文件中。 |