什么会导致Java编译器在解析注释时失败?

什么会导致Java编译器在解析注释时失败?,java,unicode,comments,grammar,lexical-analysis,Java,Unicode,Comments,Grammar,Lexical Analysis,下面的代码是一个有效的Java程序 public class Foo { public static void \u006d\u0061\u0069\u006e(String[] args) { System.out.println("hello, world"); } } main标识符是使用Unicode转义序列编写的。它编译和运行良好 $ javac Foo.java && java Foo hello, world 虽然下面的细

下面的代码是一个有效的Java程序

public class Foo
{
    public static void \u006d\u0061\u0069\u006e(String[] args)
    {
        System.out.println("hello, world");
    }
}
main
标识符是使用Unicode转义序列编写的。它编译和运行良好

$ javac Foo.java && java Foo
hello, world
虽然下面的细节对于这个问题可能不是必需的,但我还是分享它,以防有人对此感到好奇。我在Debian8.0上使用OpenJDK的Java编译器,但我在这个问题上提出的问题应该适用于任何Java编译器

$ javac -version
javac 1.7.0_79
$ readlink -f $(which javac)
/usr/lib/jvm/java-7-openjdk-amd64/bin/javac
以下程序出错,因为用于写入
main
m
的转义序列无效

public class Foo
{
    public static void \u6d\u0061\u0069\u006e(String[] args)
    {
        System.out.println("hello, world");
    }
}
编译器抱怨unicode序列非法

$ javac Foo.java && java Foo
Foo.java:3: error: illegal unicode escape
    public static void \u6d\u0061\u0069\u006e(String[] args)
                           ^
Foo.java:3: error: invalid method declaration; return type required
    public static void \u6d\u0061\u0069\u006e(String[] args)
                            ^
2 error
令我惊讶的是,下面的程序也是无效的,尽管非法的unicode转义序列似乎出现在注释中

public class Foo
{
    // This comment contains \u6d.
    public static void main(String[] args)
    {
        System.out.println("hello, world");
    }
}
这里是错误

$ javac Foo.java && java Foo
Foo.java:3: error: illegal unicode escape
    // This comment contains \u6d.
                                 ^
1 error
编译器抱怨unicode转义序列非法,尽管它似乎在注释中

public class Foo
{
    // This comment contains \u6d.
    public static void main(String[] args)
    {
        System.out.println("hello, world");
    }
}
当我们看到中如何定义行末注释时,这种行为背后的原因就变得很清楚了

定义
InputCharacter
,如下所示

InputCharacter:
  UnicodeInputCharacter but not CR or LF 
UnicodeInputCharacter:
  UnicodeEscape
  RawInputCharacter

UnicodeEscape:
  \ UnicodeMarker HexDigit HexDigit HexDigit HexDigit

UnicodeMarker:
  u {u}

HexDigit:
  (one of)
  0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F

RawInputCharacter:
  any Unicode character
最后,定义
UnicodeInputCharacter
,如下所示

InputCharacter:
  UnicodeInputCharacter but not CR or LF 
UnicodeInputCharacter:
  UnicodeEscape
  RawInputCharacter

UnicodeEscape:
  \ UnicodeMarker HexDigit HexDigit HexDigit HexDigit

UnicodeMarker:
  u {u}

HexDigit:
  (one of)
  0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F

RawInputCharacter:
  any Unicode character
因此,词法分析器需要首先识别Unicode转义序列以识别注释,如果发现非法的Unicode转义序列,词法分析将失败并发生错误。因此,编译器永远不会识别包含非法Unicode转义序列的注释

$ javac Foo.java && java Foo
Foo.java:3: error: illegal unicode escape
    public static void \u6d\u0061\u0069\u006e(String[] args)
                           ^
Foo.java:3: error: invalid method declaration; return type required
    public static void \u6d\u0061\u0069\u006e(String[] args)
                            ^
2 error
虽然我过去认为从注释开始(比如
/
)到结束的所有内容都被忽略,但上面的示例表明情况并非如此,因为词法分析器必须识别注释开始和注释结束之间的Unicode转义序列,非法的Unicode转义序列会导致词法分析失败

还有什么会导致编译器在分析注释时失败?

Short:

没有(没有其他内容)

长:

从逻辑上讲,
\u
转义序列是在词法处理(扫描/标记化)发生之前处理的。根据:

原始Unicode字符流使用以下三个词汇转换步骤转换为一系列标记,这三个步骤依次应用:

  • 将原始Unicode字符流中的Unicode转义(§3.3)转换为相应的Unicode字符。格式为\uxxx的Unicode转义,其中xxxx是十六进制值,表示编码为xxxx的UTF-16代码单元。此翻译步骤允许任何程序仅使用ASCII字符表示

  • 第1步产生的Unicode流转换为输入字符流和行终止符流(§3.4)

  • 将步骤2产生的输入字符流和行结束符翻译成一系列输入元素(§3.5),在空格(§3.6)和注释(§3.7)被丢弃后,这些元素包括作为句法语法(§2.3)终端符号的标记(§3.5)

  • 因此,从技术上讲,示例中的
    \u6d
    不是注释的一部分。在将其翻译回unicode代码点后,将确定它是否属于该注释。但不幸的是,它失败了

    作为证明,应编译以下类:

    public class Test {
        // is comment, the rest, not\u000a public static void main( String[] args) {
            System.out.println("See!");
        }
    }
    

    look@Dando18谢谢分享链接。然而,没有一个答案能真正回答这个问题。关于
    @deprecated
    的答案在OpenJDK中是不可复制的。由于此Unicode字符'*/'*/而提到
    /*编译器错误的答案是不正确的,因为后面的
    */
    显然不在注释中。其他两个答案并没有解决所问的具体问题。实际上,
    @deprecated
    答案可以使用
    javac-Xlint
    复制(前提是
    @deprecated
    在javadoc注释中(
    /**@deprecated*/
    )@realpoint你能分享一下你在javadoc评论中使用
    @deprecated
    ,然后用
    javac-Xlint
    编译的代码和错误吗?我无法用复制任何错误。我用
    javac-Xlint
    以及
    javac-Xlint编译了它,但没有发生任何错误。我想你应该是这样的强调为什么JLS的这一部分意味着没有其他东西会导致评论中出现错误,更不用说OP似乎已经理解的错误原因了。