java - 为什么在允许某些Unicode字符的注释中执行Java代码?

以下代码生成输出“hello world!”(不,真的,试试看)。

public static void main(String... args) {

   // The comment below is not a typo.
   // \u000d System.out.println("Hello World!");
}

其原因是Java编译器将Unicode字符\u000d作为新行解析并转换成:
public static void main(String... args) {

   // The comment below is not a typo.
   //
   System.out.println("Hello World!");
}

从而导致“执行”注释。
既然这可以用来“隐藏”恶意代码或者恶意程序员能想到的任何东西,为什么在注释中允许这样做?
为什么Java规范允许这样做?


最佳答案:

Unicode解码发生在任何其他词汇翻译之前。这样做的主要好处是,在ASCII和任何其他编码之间来回切换都很简单。你甚至不需要弄清楚评论从哪里开始和结束!
JLS Section 3.3中所述,这允许任何基于ASCII的工具处理源文件:
[java]编程语言指定将Unicode编写的程序转换为ASCII的标准方法,它将程序更改为可以由基于ASCII的工具处理的表单。[…]
这为平台独立性(支持字符集的独立性)提供了基本保证,这一直是Java平台的一个关键目标。
在用非拉丁语编写代码文档时,能够在文件中的任何位置编写任何Unicode字符是一个很好的特性,在注释中尤其重要。它能以如此微妙的方式干扰语义,这只是(不幸的)副作用。
在这个主题上有很多gotchas,Joshua Bloch和Neal Gafter的Java Puzzlers包括以下变体:
这是一个合法的Java程序吗?如果是,它会打印什么?

\u0070\u0075\u0062\u006c\u0069\u0063\u0020\u0020\u0020\u0020
\u0063\u006c\u0061\u0073\u0073\u0020\u0055\u0067\u006c\u0079
\u007b\u0070\u0075\u0062\u006c\u0069\u0063\u0020\u0020\u0020
\u0020\u0020\u0020\u0020\u0073\u0074\u0061\u0074\u0069\u0063
\u0076\u006f\u0069\u0064\u0020\u006d\u0061\u0069\u006e\u0028
\u0053\u0074\u0072\u0069\u006e\u0067\u005b\u005d\u0020\u0020
\u0020\u0020\u0020\u0020\u0061\u0072\u0067\u0073\u0029\u007b
\u0053\u0079\u0073\u0074\u0065\u006d\u002e\u006f\u0075\u0074
\u002e\u0070\u0072\u0069\u006e\u0074\u006c\u006e\u0028\u0020
\u0022\u0048\u0065\u006c\u006c\u006f\u0020\u0077\u0022\u002b
\u0022\u006f\u0072\u006c\u0064\u0022\u0029\u003b\u007d\u007d

(这是一个简单的“你好世界”节目。)
在解题中,他们指出了以下几点:
更严重的是,这个拼图强化了前三个方面的经验:当需要在程序中插入无法以任何其他方式表示的字符时,Unicode转义是必不可少的。在所有其他情况下都要避免。
资料来源:Java: Executing code in comments?!