57

我今天(再次)偶然发现了这个:

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

它不编译:

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

编译器似乎坚持让我写 '\n' 代替。我看不出这是为什么,但这烦人。

为什么在 Java 源代码中必须以这种形式表示具有特殊符号(如\t, \n, \r)的字符是否有逻辑解释?

4

5 回答 5

85

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 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);
        }
    }
}
于 2013-03-07T16:12:44.280 回答
23

\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

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

于 2013-03-07T16:13:33.423 回答
4

我认为原因是\uXXXX在解析代码时会扩展序列,请参阅JLS §3.2。词汇翻译

于 2013-03-07T16:14:12.497 回答
4

它在 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 = '
';
于 2013-03-07T16:23:14.623 回答
2

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

这是有效的代码:

 class \u00C9 {}
于 2013-03-07T16:13:40.330 回答