我今天(再次)偶然发现了这个:
class Test {
char ok = '\n';
char okAsWell = '\u000B';
char error = '\u000A';
}
它不编译:
第 4 行中的字符常量无效。
编译器似乎坚持让我写 '\n' 代替。我看不出这是为什么,但这很烦人。
为什么在 Java 源代码中必须以这种形式表示具有特殊符号(如\t, \n, \r)的字符是否有逻辑解释?
我今天(再次)偶然发现了这个:
class Test {
char ok = '\n';
char okAsWell = '\u000B';
char error = '\u000A';
}
它不编译:
第 4 行中的字符常量无效。
编译器似乎坚持让我写 '\n' 代替。我看不出这是为什么,但这很烦人。
为什么在 Java 源代码中必须以这种形式表示具有特殊符号(如\t, \n, \r)的字符是否有逻辑解释?
Unicode 字符被它们的值替换,所以你的行被编译器替换为:
char error = '
';
这不是有效的 Java 语句。
这是由语言规范规定的:
Java 编程语言的编译器(“Java 编译器”)首先识别其输入中的 Unicode 转义,将 ASCII 字符 \u 后跟四个十六进制数字转换为指示的十六进制值的 UTF-16 代码单元(第 3.1 节),并且传递所有其他字符不变。表示补充字符需要两个连续的 Unicode 转义符。此翻译步骤产生一系列 Unicode 输入字符。
这可能会导致令人惊讶的事情,例如,这是一个有效的 Java 程序(它包含隐藏的 unicode 字符)——由 Peter Lawrey 提供:
public static void main(String[] args) {
for (char ch = 0; ch < Character.MAX_VALUE; ch++) {
if (Character.isJavaIdentifierPart(ch) && !Character.isJavaIdentifierStart(ch)) {
System.out.printf("%04x <%s>%n", (int) ch, "" + ch);
}
}
}
\u000a在 Java 编译器对源代码执行任何其他操作之前,Unicode 转义序列会被它们所代表的实际字符替换。因此,您的程序最终会在
char ch = '
';
因此\u000a,您的源代码中的 内部将替换为换行符。请注意,这发生在编译器实际读取和解释您的源代码之前。
参考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
其他可能导致问题的符号是\,例如。'"
我认为原因是\uXXXX在解析代码时会扩展序列,请参阅JLS §3.2。词汇翻译。
它在 3.3 中描述。Unicode 转义http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html。Javac 首先在 .java 中找到 \uxxxx 序列并用真实字符替换它们然后编译。的情况下
char error = '\u000A';
\u000A 将替换为newline字符代码(10),实际文本将是
char error = '
';
因为编译器将它们视为未转义的文本。
这是有效的代码:
class \u00C9 {}