为什么一些ASCII字符不能在Java源代码中以“\ uXXXX”的forms表示?

今天我又偶然发现了这个:

class Test { char ok = '\n'; char okAsWell = '\u000B'; char error = '\u000A'; } 

它不会编译:

第4行中的字符常量无效。

编译器似乎坚持我写'\ n'来代替。 我看不出有什么理由,但这烦人。

是否有一个合乎逻辑的解释,为什么具有特殊符号的字符(如\t\n\r必须以Java源代码的formsexpression?

Unicode字符被它们的值replace,所以你的行被编译器replace:

 char error = ' '; 

这不是一个有效的Java语句。

这是语言规范所规定的:

用于Java编程语言(“Java编译器”)的编译器首先识别其input中的Unicode转义,将ASCII字符\ u后跟四个hex数字转换为指定的hex值的UTF-16代码单元(第3.1节)所有其他字符不变。 表示补充字符需要连续两次Unicode转义。 该翻译步骤产生一系列Unicodeinput字符。

这可能会导致令人惊讶的东西,例如,这是一个有效的Java程序(它包含隐藏的Unicode字符) – 彼得·劳瑞礼貌 :

 public static void main(String[] args) { for (char c‮h = 0; c‮h < Character.MAX_VALUE; c‮h++) { if (Character.isJavaIdentifierPart(c‮h) && !Character.isJavaIdentifierStart(c‮h)) { System.out.printf("%04x <%s>%n", (int) c‮h, "" + c‮h); } } } 

在Java编译器对源代码执行其他任何操作之前, \u000a这样的Unicode转义序列被它们代表的实际字符replace 。 所以,你的程序最终会以

 char ch = ' '; 

因此,源代码中的\u000a在内部被一个换行字符replace。 请注意,这是在编译器实际读取和解释源代码之前发生的。

参考Java语言规范 :

对于行结束符 (§3.4)出现在“结束之前”和“结束之前”是一个编译时错误。

而且所有人都知道, \n是一个行结束符 ,引用:

  LineTerminator: the ASCII LF character, also known as "newline" the ASCII CR character, also known as "return" the ASCII CR character followed by the ASCII LF character 

其他可能导致问题的符号是"'"例如。

我认为原因是在parsing代码时扩展了\uXXXX序列,参见JLS§3.2。 词汇翻译 。

在3.3中描述。 Unicode转义http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html 。 Javac首先在.java中find\ uxxxx序列,并用真正的字符replace它们然后编译。 的情况下

 char error = '\u000A'; 

\ u000A将被replace为newline (10),实际的文本将会被replace

 char error = ' '; 

因为编译器将它们视为未转义的文本。

这是有效的代码:

  class \u00C9 {}