我今天(再次)偶然发现了这个:
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 {}