Java语言规范(Java SE 22)章3 词法结构

本章详细说明了 Java 编程语言的词法结构。

程序是用 Unicode (§3.1) 编写的,但提供了词法翻译 (§3.2),以便可以使用 Unicode 转义符 (§3.3) 来包含仅使用 ASCII 字符的任何 Unicode 字符。行终止符的定义(第 3.4 节)是为了支持现有主机系统的不同约定,同时保持一致的行号。

词汇翻译产生的 Unicode 字符被简化为一系列输入元素 (§3.5),其中包括空格 (§3.6)、注释 (§3.7) 和标记。标记是句法语法的标识符(第 3.8 节)、关键字(第 3.9 节)、字面量(第 3.10 节)、分隔符(第 3.11 节)和运算符(第 3.12 节)。

3.1 Unicode

程序是使用 Unicode 字符集 (§1.7) 编写的。有关此字符集及其相关字符编码的信息,请参阅 https:// www.unicode.org/。

Java SE 平台跟踪 Unicode 标准的发展。给定版本使用的 Unicode 的精确版本在类 Character 的文档中指定。

Unicode 标准最初设计为固定宽度的 16 位字符编码。此后,它已更改为允许表示需要超过 16 位的字符。合法的代码点的范围现在是 U+0000 到 U +10FFFF,使用十六进制 U+n 表示法。码位大于 U+FFFF 的字符称为补充字符。为了仅使用 16 位单位表示完整的字符范围,Unicode 标准定义了一种称为 UTF-16 的编码。在此编码中,增补字符表示为一对 16 位代码单元,第一个来自高代理项范围(U+D800 到 U+DBFF),第二个来自低代理项范围(U+DC00 到 U+DFFF)。对于 U+0000 到 U+FFFF 范围内的字符,码位和 UTF-16 码单元的值相同。

Java 编程语言使用 UTF-16 编码以 16 位代码单元序列表示文本。

Java SE 平台的一些 API,主要是在 Character 类中,使用 32 位整数将代码点表示为单个实体。Java SE 平台提供了在 16 位和 32 位表示之间进行转换的方法。

本规范使用术语代码点和 UTF-16 代码单元来表示与当前讨论相关的情况,而通用术语字符(character)表示与当前讨论无关的情况。

除了注释(第 3.7 节)、标识符(第 3.8 节)以及字符字面值、字符串字面值和文本块的内容(第 3.10.4 节、第 3.10.5 节、第 3.10.6 节)外,程序中的所有输入元素(第 3.5 节)仅由 ASCII 字符(或生成 ASCII 字符的 Unicode 转义字符(第 3.3 节))组成。

ASCII (ANSI X3.4) 是美国信息交换标准码,Unicode UTF-16编码的前128个字符就是ASCII字符。

3.2 词法翻译

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

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

2. 将步骤 1 产生的 Unicode 流转换为输入字符和行终止符的流(第 3.4 节)。

3. 将步骤 2 产生的输入字符流和行终止符转换为输入元素序列 (§3.5),在丢弃空格 (§3.6) 和注释 (§3.7) 后,这些元素包含以下标记:句法语法的终止符号(§2.3)。

每一步都使用尽可能长的翻译,即使结果最终不会产生正确的程序,而采用另一种词汇翻译可能会产生可用的程序。有两个例外情况需要更精细的翻译:在步骤1中,用于处理连续的\字符(第3.3节),在步骤3中,用于处理上下文关键字和相邻的>字符(第3.5节)。

输入字符 a--b 被翻译为 a、--, 和 b,它们不是任何语法正确的程序的一部分,即使分词 a、-, -, b 可能是语法正确的程序的一部分。分词 a -, -, b 可以通过输入字符 a- -b 实现(两个 - 字符之间有一个 ASCII SP 字符)。

可以假设原始输入 \\u1234 被转换为 \ 字符和(遵循“最长可能”规则)格式为 \u1234 的 Unicode 转义。事实上,前导 \ 字符使此原始输入被转换为七个不同的字符:\ \ u 1 2 3 4。

3.3 Unicode转义

Java 编程语言的编译器(“Java 编译器”)首先识别其原始输入中的 Unicode 转义,将 ASCII 字符 \u 后跟四个十六进制数字转换为表示 UTF-16 代码单元的原始输入字符(第 3.1 节) 为指示的十六进制值。 一个 Unicode 转义符可以表示 U0000 到 UFFFF 范围内的字符;表示 U010000 到 U10FFFF 范围内的增补字符需要两个连续的 Unicode 转义。 编译器原始输入中的所有其他字符都被识别为原始输入字符并按原样传递。

此转换步骤会产生 Unicode 输入字符序列,所有这些字符都是原始输入字符(任何 Unicode 转义都已简化为原始输入字符)。

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

这里的\、u、十六进制数字都是ASCII字符。

UnicodeInputCharacter 的生成式是不明确的,因为 编译器原始输入中的 \ 字符可以推导为
RawInputCharacter UnicodeEscape 的 \(后跟 ASCII u)。为了避免歧义,对于编译器原始输入中的每个 ASCII \ 字符,输入处理必须考虑最近产生的原始输入字符,具体步骤如下:

  • 如果结果中最新的原始输入字符本身是从编译器原始输入中的 Unicode 转义转换而来的,则 ASCII \ 字符有资格开始 Unicode 转义。

例如,如果结果中最新的原始输入字符是由原始输入中的 Unicode 转义 \u005c 产生的 \,则原始输入中接下来出现的 ASCII \ 字符有资格开始另一个 Unicode 转义。

  • 否则,考虑有多少个反斜杠作为原始输入连续出现结果中的字符,则对改反斜杠前直到非反斜杠字符或结果的开头的反斜杠进行计数。(至于此类反斜杠是源于 ASCII \ 字符还是来自编译器原始中的 Unicode 转义 \u005c输入并不重要。)如果该数字是偶数,则 ASCII \ 字符有资格开始一个Unicode 转义; 如果数字是奇数,则 ASCII \ 字符不能开始 Unicode 转义

例如,原始输入“\\u2122=\u2122”会生成十一个字符“\\ u 2 1 2 2 = ™”,因为原始输入中的第二个 ASCII \ 字符不符合开始 Unicode 转义的条件, 第三个 ASCII \ 字符是合格的,\u2122 是字符 ™ 的 Unicode 编码。

如果符合条件的 \ 后面没有 u,则它被视为 RawInputCharacter 并保留为转义 Unicode 流的一部分。

如果符合条件的 \ 后面跟着 u,或者多个 u,并且最后一个 u 后面没有跟着四个十六进制数字,则会出现编译时错误。

Unicode 转义产生的字符不参与进一步的 Unicode 转义。

例如,原始输入 \u005cu005a 会生成六个字符 \ u 0 0 5 a,因为005c 是反斜杠的 Unicode 值。 它不会产生字符 Z(Unicode 值 005a) ,因为处理 Unicode转义时产生的反斜杠不会被解释为进一步 Unicode 转义的开始。

请注意,\u005cu005a 不能写成字符串文字来表示六个字符 \ u 0 0 5 a。 这是因为翻译产生的前两个字符 \ 和 u 在字符串字面值中被解释为非法转义序列(第 3.10.7 节)。

幸运的是,有关连续反斜杠字符的规则可以帮助程序员制作原始输入,以采用字符串字面值方式表示 Unicode 转义。 在字符串字面值中表示六个字符 \ u 0 0 5 a 只需要在现有 \ 旁边放置另一个 \,例如“\\u005a is Z”。 这是有效的,因为原始输入 \\u005a 中的第二个 \ 不符合开始 Unicode 转义的条件,因此第一个 \ 和第二个 \ 被保留为原始输入字符,接下来的五个字符 u 0 0 5 a 也是如此。 随后,两个 \ 字符在字符串字面值中被解释为反斜杠的转义序列,从而生成具有所需六个字符 \ u 0 0 5 a 的字符串。 如果没有该规则,原始输入 \\u005a 将被处理为原始输入字符 \,后跟 Unicode 转义 \u005a,后者成为原始输入字符 Z; 这将没有帮助,因为 \Z 是字符串文字中的非法转义序列。 (请注意,该规则将 \u005c\u005c 转换为 \\,因为将第一个 Unicode 转义符转换为原始输入字符 \ 不会阻止第二个 Unicode 转义符转换为另一个原始输入字符 \。)

该规则还允许程序员制作原始输入,表示转义序列字符串字面量。 例如,原始输入 \\\u006e 会生成三个字符 \\ n因为第一个 \ 和第二个 \ 被保留为原始输入字符,而第三个 \有资格开始 Unicode 转义,因此 \u006e 被转换为原始输入字符n,这 三个字符 \\ n 随后在字符串字面值中解释为 \ n ,其中表示换行符的转义序列。 (请注意,\\\u006e 可以写为 \u005c\u005c\u006e 因为每个 Unicode 转义 \u005c 都会转换为原始输入字符\ 因此剩余的原始输入 \u006e 前面有偶数个反斜杠并作为 n 的 Unicode 转义进行处理。)

Java 编程语言指定了一种将用 Unicode 编写的程序转换为 ASCII 的标准方法,该方法将程序转换为可以由基于 ASCII 的工具处理的形式。 该转换涉及通过添加额外的 u 将程序源文本中的任何 Unicode 转义符转换为 ASCII(例如,\uxxxx 变为 \uuxxxx),同时将源文本中的非 ASCII 字符转换为每个包含一个 u 的 Unicode 转义符。

这个转换后的版本同样可以被 Java 编译器接受,并且代表完全相同的程序。 稍后可以通过将存在多个 u 的每个转义序列转换为少一个 u 的 Unicode 字符序列,同时将具有单个 u 的每个转义序列转换为相应的单个 Unicode 字符,从而从此 ASCII 形式恢复确切的 Unicode 源码。

当没有合适的字体可用时,Java 编译器应使用 \uxxxx 表示法作为输出格式来显示 Unicode 字符。

3.4 换行符

接下来,Java 编译器通过识别行终止符将 Unicode 输入字符序列划分为行。

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

InputCharacter:

        UnicodeInputCharacter but not CR or LF

行以 ASCII 字符 CR、LF 或 CR LF 结尾。紧跟 LF 的两个字符 CR 算作一行终止符,而不是两个。

行终止符指定注释的 // 形式的终止 (§3.7)。

行终止符定义的行可以确定 Java 编译器生成的行号。

结果是一系列行终止符和输入字符,它们是分词过程第三步的终端符号。

3.5 输入元素和标记

Unicode 转义处理 (§3.3) 和输入行识别 (§3.4) 产生的输入字符和行终止符将简化为一系列输入元素。

Input:

        {InputElement} [Sub]

InputElement:

        WhiteSpace

        Comment

        Token

Token:

        Identifier

        Keyword

        Literal

        Separator

        Operator

Sub:

        the ASCII SUB character, also known as "control-Z"

那些不是空格或注释的输入元素是标记。标记是句法语法的终端符号 (§2.3)。

空格 (§3.6) 和注释 (§3.7) 可以用于分隔标记,如果相邻,则可能会分词为其他形式。

例如,输入字符 - 和 = 只有在没有中间空格或注释的情况下才能构成运算符标记 -= (§3.12)。再举一个例子,10 个输入字符 staticvoid 形成一个标识符标记,而 11 个输入字符 static void(在 c 和 v 之间有一个 ASCII SP 字符)形成一对关键字标记,static 和 void,用空格分隔。

作为与某些操作系统兼容性的特殊让步,如果 ASCII SUB 字符(\u001a 或 control-Z)是转义输入流中的最后一个字符,则忽略该字符。

输入产生式是不明确的,这意味着对于某些输入字符序列,有不止一种方法可以将输入字符推导为输入元素(即对输入字符进行标记)。歧义的解决如下:

  • 可以解释为标识符标记或文字标记的输入字符序列始终会简化为文字标记。
  • 可以解释为标识符标记或保留关键字标记(§3.9)的输入字符序列始终会简化为保留关键字标记。
  • 可以解释为上下文关键字标记或其他(非关键字)标记的输入字符序列,如第 3.9 节中所指定。
  • 如果输入字符 > 出现在类型上下文中(第 4.11 节),即作为句法语法中 Type 或 UnannType 的一部分(第 4.1 节,第 8.3 节),它始终会解释为数字比较运算符 >,甚至当它可以与相邻的 > 字符组合形成不同的运算符时。(啥意思呢,这里不应该是解释成类型的一部分吗?)

如果没有 > 字符的这条规则,在 List<List<String>> 等类型中,连续两个 > 括号将被标记为有符号右移运算符 >>,而 List<List<List<String>>>等类型中连续三个 > 括号将被标记为无符号右移运算符 >>>。更糟糕的是,在 List<List<List<List<String>>>> 等类型中连续四个或更多个 > 括号的标记会产生歧义,因为 >、>> 和 >>> 标记的各种组合可以表示 >>>> 字符。

考虑输入流中的两个标记 x 和 y。如果 x 在 y 之前,那么我们说 x 在 y 的左边,y 在 x 的右边。

例如,对于如下简单的代码:

class Empty {
}

我们说 } 标记在 { 标记的右边,即使在这个二维表示中,它出现在 { 标记的下方和左侧。这种关于左和右使用的约定允许我们谈论如二进制运算符的右操作数或赋值的左侧等。

3.6 空白

空白被定义为 ASCII 空格字符、水平制表符、表单输入字符和行结束符字符(第 3.4 节)。

WhiteSpace:

        the ASCII SP character, also known as "space"

         the ASCII HT character, also known as "horizontal tab"

        the ASCII FF character, also known as "form feed"

        LineTerminator

3.7 注释

有两种类型的注视:

  • /* 注释内容 */

        传统的注释:从 ASCII 字符 /* 到 ASCII 字符 */ 的所有文本都被忽略(如 C 和 C++)。

  • // 注释内容

        行尾注释:从ASCII字符//到行尾的所有文本都被忽略(如C ++)。

Comment:

        TraditionalComment

        EndOfLineComment

TraditionalComment:

        / * CommentTail

CommentTail:

        * CommentTailStar

        NotStar CommentTail

CommentTailStar:

        /

        * CommentTailStar

         NotStarNotSlash

        CommentTail

NotStar:

        InputCharacter but not *

        LineTerminator

NotStarNotSlash:

        InputCharacter but not * or /

        LineTerminator

EndOfLineComment:

        / / {InputCharacter}

这些生成式有如下要求:

  • 注释不能嵌套。
  • /* 和 */ 在以 // 开头的注释中没有特殊含义。
  • // 在以 /* 或 /** 开头的注释中没有特殊含义。

因此,以下文本只是一个完整的注释:

/* this comment /* // /** ends here: */

词法语法意味着注释不会出现在字符字面量、字符串字面量或文本块中(第 3.10.4、第 3.10.5、第 3.10.6 节)。

3.8 标识符

标识符是由 Java 字母和 Java 数字组成的无限长度的序列,其中第一个必须是 Java 字母。

Identifier:

        IdentifierChars but not a ReservedKeyword or BooleanLiteral or NullLiteral

IdentifierChars:

        JavaLetter {JavaLetterOrDigit}

JavaLetter:

        any Unicode character that is a "Java letter"

JavaLetterOrDigit:

        any Unicode character that is a "Java letter-or-digit"

“Java letter”就是那些Character.isJavaIdentifierStart(int)返回true的字符。“Java letter-or-digit”是Character.isJavaIdentifierPart(int)返回true的字符。

"Java letters"包括大写和小写ASCII拉丁字母A-Z(\u0041\u005a)和a-z(\u0061-\u007a),以及由于历史原因,ASCII美元符号($或\u0024)和下划线(_或\u005f)。美元符号应仅用于机械生成的源代码,或者用于访问遗留系统上已有的名称。下划线可用于由两个或更多字符组成的标识符,但由于是关键字,因此不能用作单字符标识符。

"Java digits"包括ASCII数字0-9(\u0030-\u0039)。

字母和数字可以从整个Unicode字符集中提取,该字符集支持当今世界上使用的大多数书写脚本,包括中文,日文和韩文的大型集。这允许程序员在他们的程序中使用用母语编写的标识符。

只有在忽略可忽略字符后,标识符的每个字母或数字具有相同的 Unicode 字符时,两个标识符才相同。可忽略字符是 Character.isIdentifierIgnorable(int) 方法返回 true 的字符。具有相同外部外观的标识符可能不同。

例如,由单个字母组成的标识符,拉丁大写字母A (A,\u0041) 、拉丁小写字母A (a,\u0061) 、希腊大写字母ALPHA (A,\u0391) 、CYRILLIC SMALL LETTER A (a,\u0430) 和MATHEMATICAL BOLD ITALIC SMALL A (a,\ud835\udc82) 都是不同的。

Unicode复合字符与它们的规范等效分解字符不同。例如,拉丁大写字母A ACUTE (Á,\u00c1) 与紧随其后的拉丁大写字母A (A,\u0041) 和NONSPACING ACUTE ( ́,\u0301) 在标识符中不同。参见 Unicode 标准,第 3.11 节"规范化形式"。

举几个标识符的例子:

  • String
  • i3
  • αρετη
  • MAX_VALUE
  • isLetterOrDigit

由于标记化规则(第 3.5 节),标识符的拼写(Unicode 字符序列)永远不会与保留关键字(第 3.9 节)、布尔文字(第 3.10.3 节)或null字面值(第 3.10.8 节)相同。但是,标识符的拼写可能与上下文关键字相同,因为将输入字符序列标记为标识符或上下文关键字取决于该序列在程序中的出现位置。

为了便于识别上下文关键词,句法语法(第2.3节)有时会通过定义一个生成式只接受一个标识符子集来禁止某些标识符。子集如下:

TypeIdentifier:

        Identifier but not permits, record, sealed, var, or yield

UnqualifiedMethodIdentifier:

        Identifier but not yield

TypeIdentifier 用于声明类、接口和类型参数(第 8.1 节、第 9.1 节、第 4.4 节)以及引用类型(第 6.5 节)。例如,类的名称必须是 TypeIdentifier,因此声明名为 permits、record、sealed、var 或 yield 的类是非法的。

UnqualifiedMethodIdentifier 用于方法调用表达式通过其简单名称引用方法(第 6.5.7.1 节)。由于从 UnqualifiedMethodIdentifier 中排除了 yield 术语,因此必须对任何名为 yield 的方法调用进行限定,从而将调用与 yield 语句区分开来(第 14.21 节)。

3.9 关键字

由ASCII字符组成的51个字符序列被保留用作关键字,不能用作标识符(第3.8节)。另外17个字符序列,也由ASCII字符组成,可以解释为关键字或其他标记,具体取决于它们出现的上下文。

Keyword:

        ReservedKeyword

        ContextualKeyword

ReservedKeyword:

        (one of)

        abstract        continue      for                  new               switch

        assert           default         if                    package        synchronized

        boolean        do               goto                private           this

        break            double        implements     protected      throw

        byte              else             import             public           throws

        case             enum           instanceof      return            transient

        catch            extends       int                   short             try

        char              final             interface         static            void

        class             finally          long                strictfp          volatile

        const             float            native             super            while

         _ (underscore)

        

ContextualKeyword:

        (one of)

        exports              opens          requires        uses        yield

        module              permits        sealed           var

        non-sealed        provides       to                  when

        opne                  record          transitive        with

        

关键字const和goto是保留的,即使它们目前没有被使用。如果这些C ++关键字错误地出现在程序中,这可能会使Java编译器产生更好的错误消息。

关键字strictfp已经过时,不应在新代码中使用。

关键字_(下划线)可以在某些声明中使用,以代替标识符(第6.1节)。

true和false不是关键字,而是布尔字面量(第3.10.3节)。

null不是关键字,而是空字面量(第3.10.8节)。

在将输入字符还原为输入元素(第 3.5 节)的过程中,当且仅当以下两个条件成立时,概念上匹配上下文关键字的输入字符序列将还原为上下文关键字:

1. 该序列被识别为在句法语法(第2.3节)的合适上下文中指定的终端,如下所示:

  • 对于 module 和 open,当在 ModuleDeclaration(第 7.7 节)中识别为终端时。
  • 对于 export、opens、provides、requires、to、uses 和 with,当在 ModuleDirective 中识别为终端时。
  • 对于transitive,当在RequiresModifier中识别为终端时。
  • 对于 var,当识别为 LocalVariableType (§14.4) 或 LambdaParameterType (§15.27.1) 中的终端时。
  • 对于 yield,当在 YieldStatement (14.21) 中识别为终端时。
  • 作为record,当在RecordDeclaration(第 8.10 条)中被识别为终端时。
  • 对于non-sealed、permits和sealed,当在NormalClassDeclaration (§8.1) 或NormalInterfaceDeclaration (§9.1) 中识别为终端时。
  • 对于when,当前在Guard(§14.11.1)中被识别为终端时。

2. 该序列之前或之后没有与 JavaLetterOrDigit 匹配的输入字符

 一般来说,由于“最长可能的翻译”规则(第 3.2 节),意外地省略源代码中的空格将导致输入字符序列被标记为标识符。例如,十二个输入字符的序列 publicstatic 始终被标记为标识符 publicstatic,而不是保留关键字 public 和 static。如果打算使用两个标记,则必须用空格或注释分隔它们。

上述规则与“最长可能翻译”规则协同工作,以在可能出现上下文关键字的上下文中产生直观的结果。例如,十一个输入字符的序列 varfilename 通常被标记为标识符 varfilename,但在局部变量声明中,前三个输入字符被上述规则的第一个条件暂时识别为上下文关键字 var。然而,通过将接下来的八个输入字符识别为标识符文件名来忽略序列中缺少空格的情况会令人困惑。(这意味着序列在不同的上下文中经历不同的标记化:大多数上下文中是标识符,但局部变量声明中是上下文关键字和标识符。)因此,第二个条件阻止识别上下文关键字 var,因为紧接着输入字符 f 的是 JavaLetterOrDigit。因此,序列 varfilename 在局部变量声明中被标记为标识符 varfilename。

作为仔细识别上下文关键字的另一个示例,请考虑 15 个n o n - s e a l e d c l a s s输入字符的序列。该序列通常被翻译为三个标记: 标识符 non、运算符 - 和标识符 sealclass,但在正常的类声明中,第一个条件成立时,前十个输入字符暂时被识别为上下文关键字 non-sealed 。为了避免将序列转换为两个关键字标记(non-sealed和class)而不是三个非关键字标记,并避免奖励程序员在class之前省略空格,第二个条件阻止识别上下文关键字。因此,n o n - s e a l e d c l a s s序列在类声明中被标记为三个标记。

在上面的规则中,第一个条件取决于句法语法的细节,但是Java编程语言的编译器可以在不完全解析输入程序的情况下实现该规则。例如,启发式可用于跟踪分词器的上下文状态,只要启发式保证上下文关键字的有效使用被标记为关键字,并且标识符的有效使用被标记为标识符。或者,编译器始终可以将上下文关键字标记为标识符,将其留到稍后阶段来识别这些标识符的特殊用途。

3.10 字面量

 字面量是基本类型 (§4.2)、String 类型 (§4.3.3) 或 null 类型 (§4.1) 值的源代码表示形式。

Literal:

        IntegerLiteral

        FloatingPointLiteral

        BooleanLiteral

        CharacterLiteral

        StringLiteral

        TextBlock

        NullLiteral

3.10.1 整型字面量

整型字面量可以用十进制(以 10 为基数)、十六进制(以 16 为基数)、八进制(以 8 为基数)或二进制(以 2 为基数)表示。

IntegerLiteral:

        DecimalIntegerLiteral

        HexIntegerLiteral

        OctalIntegerLiteral

        BinaryIntegerLiteral

DecimalIntegerLiteral:

        DecimalNumeral [IntegerTypeSuffix]

HexIntegerLiteral:

        HexNumeral [IntegerTypeSuffix]

OctalIntegerLiteral:

        OctalNumeral [IntegerTypeSuffix]

BinaryIntegerLiteral:

        BinaryNumeral [IntegerTypeSuffix]

IntegerTypeSuffix:

        (one of)

        l L

如果整型字面量以 ASCII 字母 L 或 l (ell) 为后缀,则该整型的类型为 long;否则,它的类型为 int (§4.2.1)。

后缀 L 是首选,因为字母 l (ell) 通常很难与数字 1 (一) 区分开来。

下划线允许用作表示整数的数字之间的分隔符。

在十六进制或二进制文本中,整数仅由 0x 或 0b 字符和类型后缀之间的数字表示。因此,下划线不会立即出现在 0x 或 0b 之后,或者数字中的最后一位数字之后。

在十进制或八进制文本中,整数由类型后缀之前的所有数字表示。因此,下划线可能不会出现在数字的第一个数字之前或最后一个数字之后。下划线可能出现在八进制数字的初始 0 之后(因为 0 是表示整数部分的数字)和非零十进制文字中的初始非零数字之后。

十进制数字是单个 ASCII 数字 0,表示整数零,或者由一个从 1 到 9 的 ASCII 数字组成,可以选择后跟一个或多个从 0 到 9 的 ASCII 数字,中间穿插着下划线,表示正整数。

DecimalNumeral:

        0

        NonZeroDigit [Digits]

        NonZeroDigit Underscores Digits

NonZeroDigit:

        (one of)

        1 2 3 4 5 6 7 8 9

Digits:

        Digit

        Digit [DigitsAndUnderscores] Digit

Digit:

        0

        NonZeroDigit

DigitsAndUnderscores:

        DigitOrUnderscore {DigitOrUnderscore}

DigitOrUnderscore:

        Digit

        _

Underscores:

        _ {_}

十六进制数字由前导 ASCII 字符 0x 或 0X 组成,后跟一个或多个穿插下划线的 ASCII 十六进制数字,可以表示正整数、零整数或负整数。

值为 10 到 15 的十六进制数字分别用 ASCII 字母 a 到 f 或 A 到 F 表示;用作十六进制数字的每个字母可以是大写或小写。

HexNumeral:

        0 x HexDigits

        0 X HexDigits

HexDigits:

        HexDigit

        HexDigit [HexDigitsAndUnderscores] HexDigit

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

HexDigitsAndUnderscores:

        HexDigitOrUnderscore {HexDigitOrUnderscore}

HexDigitOrUnderscore:

        HexDigit

        _

八进制数字由一个 ASCII 数字 0 ,后跟一个或多个穿插下划线的 ASCII 数字 0 到 7,可以表示正整数、零整数或负整数。

OctalNumeral:

        0 OctalDigits

        0 Underscores OctalDigits

OctalDigits:

        OctalDigit

        OctalDigit [OctalDigitsAndUnderscores] OctalDigit

OctalDigit:

        (one of)

        0 1 2 3 4 5 6 7

OctalDigitsAndUnderscores:

        OctalDigitOrUnderscore {OctalDigitOrUnderscore}

OctalDigitOrUnderscore:

        OctalDigit

        _

请注意,八进制数字总是由两个或多个数字组成,因为单独的 0 总是被认为是一个十进制数字——这在实践中并不重要,因为数字 0、00 和 0x0 都表示完全相同的整数值。

二进制数字由前导 ASCII 字符 0b 或 0B 组成,后跟一个或多个 ASCII 数字 0 或 1,并穿插着下划线,可以表示正整数、零整数或负整数。

BinaryNumeral:

        0 b BinaryDigits

        0 B BinaryDigits

BinaryDigits:

        BinaryDigit

        BinaryDigit [BinaryDigitsAndUnderscores] BinaryDigit

BinaryDigit:

        (one of)

        01

BinaryDigitsAndUnderscores:

        BinaryDigitOrUnderscore {BinaryDigitOrUnderscore}

BinaryDigitOrUnderscore:

        BinaryDigit

        _

int 类型的最大十进制字面值是 2147483648 (2^31)。

从 0 到 2147483647 的所有十进制文字都可能出现在任何可能出现 int 字面值的地方。十进制文字2147483648只能作为一元减号运算符 (§15.15.4) 的操作数出现。

如果十进制文字2147483648出现在一元减号运算符的操作数以外的任何位置,则为编译时错误;或者,如果 int 类型的十进制文字大于 2147483648 (2^31)。

int 类型的最大正十六进制、八进制和二进制字面量(每个文本都表示十进制值 2147483647 (231 -1))分别为:

  • 0x7fff_ffff
  • 0177_7777_7777
  • 0b0111_1111_1111_1111_1111_1111_1111_1111

int 类型的最负十六进制、八进制和二进制字面量 - 每个都表示十进制值 -2147483648 (-2^31) - 分别是:

  • 0x8000_0000
  • 0200_0000_0000
  • 0b1000_0000_0000_0000_0000_0000_0000_0000

以下十六进制、八进制和二进制文本表示十进制值-1:

  • 0xffff_ffff
  • 0377_7777_7777
  • 0b1111_1111_1111_1111_1111_1111_1111_1111

如果十六进制、八进制或二进制整数文字不是 32 位,则为编译时错误。

long 类型的最大十进制文字是 9223372036854775808L (2^63)。

从 0L 到 9223372036854775807L 的所有十进制文字都可能出现在长文本出现的任何位置。可能会出现十进制文字 9223372036854775808L仅作为一元减号运算符 - (§15.15.4) 的操作数。

如果十进制文字 9223372036854775808L 出现在一元减号运算符的操作数以外的任何位置,则为编译时错误;或者,如果 long 类型的十进制文本大于 9223372036854775808L (2^63)。

long 类型的最大正十六进制、八进制和二进制文本(每个字面量都表示十进制值 9223372036854775807L (2^63 -1))分别是:

  • 0x7fff_ffff_ffff_ffffL
  • 07_7777_7777_7777_7777_7777L
  • 0b0111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111L

long类型最负的十六进制、八进制和二进制文字 - 每个都表示十进制值 -9223372036854775808L (-2^63) - 分别是:

  • 0x8000_0000_0000_0000L
  • 010_0000_0000_0000_0000_0000L
  • 0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000L

以下十六进制、八进制和二进制字面量表示十进制值-1L:

  • 0xffff_ffff_ffff_ffffL
  • 017_7777_7777_7777_7777_7777L
  • 0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111L

如果十六进制、八进制或二进制long类型字面量不适合 64 位,则为编译时错误。

int类型字面量举例:

0        2        0372        0xDada_Cafe        1996        0x00_FF__00_FF

long类型字面量举例:

0l        0777L        0x100000000L        2_147_483_648L        0xC0B0L

3.10.2 浮点数字面量

浮点字面量包含以下部分:整数部分、小数点或十六进制点(由 ASCII 句点字符表示)、分数部分、指数和类型后缀。

浮点字面量可以用十进制(以 10 为基数)或十六进制(以 16 为基数)表示。

对于十进制浮点数,至少需要一位数字(在整数或分数部分)和小数点、指数或浮点类型后缀。所有其他部件都是可选的。指数(如果存在)由 ASCII 字母 e 或 E 表示,后跟可选的有符号整数。

对于十六进制浮点数,至少需要一位数字(在整数或分数部分),指数是必需的,浮点类型后缀是可选的。指数由 ASCII 字母 p 或 P 表示,后跟可选的有符号整数。

下划线可以作为表示整数部分的数字之间、表示分数部分的数字之间以及表示指数的数字之间的分隔符。

FloatingPointLiteral:

        DecimalFloatingPointLiteral

        HexadecimalFloatingPointLiteral

DecimalFloatingPointLiteral:

        Digits . [Digits] [ExponentPart] [FloatTypeSuffix]

        . Digits [ExponentPart] [FloatTypeSuffix]

        Digits ExponentPart [FloatTypeSuffix]

        Digits [ExponentPart] FloatTypeSuffix

ExponentPart:

        ExponentIndicator SignedInteger

ExponentIndicator:

        (one of)

        e E

SignedInteger:

        [Sign] Digits

Sign:

        (one of)

        + -

FloatTypeSuffix:

        (one of)

        f F d D

HexadecimalFloatingPointLiteral:

        HexSignificand BinaryExponent [FloatTypeSuffix]

HexSignificand:

        HexNumeral [.]

        0 x [HexDigits] . HexDigits

        0 X [HexDigits] . HexDigits

BinaryExponent:

        BinaryExponentIndicator SignedInteger

BinaryExponentIndicator:

        (one of)

        p P

如果浮点文字以 ASCII 字母 F 或 f 为后缀,则该浮点文字属于float类型;否则,其类型为双精度,可以选择以 ASCII 字母 D 或 d 为后缀。

float 和 double 类型的元素是可以分别使用 IEEE 754 binary32 和 IEEE 754 binary64 浮点格式表示的值 (§4.2.3)。

对于包 java.lang 的 Float 类和 Double 类的 valueOf 方法,描述了从浮点数的 Unicode 字符串表示形式到内部 IEEE 754 二进制浮点表示形式的正确输入转换的详细信息。

float 类型的最大和最小正值字面量如下:

  • 最大正有限浮点数值在数值上等于 (2 - 2^-23)⋅ 2^127。四舍五入到此值的最短十进制文本是 3.4028235e38f。此值的十六进制字面量为 0x1.fffffeP+127f。
  • 最小的正有限非零浮点数值在数值上等于 2^-149。四舍五入到此值的最短十进制文字是 1.4e-45f。此值的两个十六进制文本是 0x0.000002P-126f 和 0x1.0P-149f。

double 类型的最大和最小正字面量如下:

  • 最大正有限double值在数值上等于 (2 - 2^-52)⋅ 2^1023。四舍五入到此值的最短十进制文本是 1.7976931348623157e308。此值的十六进制文本为 0x1.f_ffff_ffff_ffffP+1023。
  • 最小的正有限非零double值在数值上等于 2^-1074。四舍五入到此值的最短十进制文字是 4.9e-324。此值的两个十六进制文本是 0x0.0_0000_0000_0001P-1022 和 0x1.0P-1074。

如果非零浮点字面量太大,则为编译时错误,因此在四舍五入转换为其内部表示形式时,它将成为 IEEE 754 无穷大。通过使用常量表达式(如 1f/0f 或 -1d/0d)或使用 Float 和 Double 类的预定义常量 POSITIVE_INFINITY 和 NEGATIVE_INFINITY,程序可以表示无穷大而不会产生编译时错误。如果非零浮点字面量太小,则为编译时错误,因此,在四舍五入转换为其内部表示形式时,它变为零。

如果非零浮点字面量具有一个小值,该值在四舍五入转换为其内部表示形式时变为非零次正态数,则不会发生编译时错误。

表示 Not-a-Number 值的预定义常量在类 Float 和 Double 中定义为 Float.NaN 和 Double.NaN。

float类型字面量举例:

1e1f        2.f        .3f        0f        3.14f        6.022137e+23f

double类型字面量举例:

1e1        2.        .3        0.0        3.14        1e-9d        1e137

3.10.3 布尔字面量

布尔类型有两个值,由ASCII 字母组成的布尔字面量 true 和 false 表示 。

BooleanLiteral:

        (one of)

        true false

布尔字面量始终是布尔类型 (§4.2.5)。

3.10.4 字符字面量

字符字面量表示为字符或转义序列 (§3.10.7),用 ASCII 单引号括起来。(单引号或撇号字符为 \u0027。

CharacterLiteral:

        ' SingleCharacter '

        ' EscapeSequence '

SingleCharacter:

        InputCharacter but not ' or \

字符字面量始终是 char 类型 (§4.2.1)。

字符字面量的内容是 SingleCharacterEscapeSequence,它跟在开头的引号(')之后.

如果内容后面的字符不是 ',则编译时错误。

行终止符 (§3.4) 出现在开始 ' 之后或结束 ' 之前是编译时错误。

字符 CR 和 LF 不是 InputCharacter;每个都被认为是构成一个 LineTerminator,因此可能不会出现在字符字面量中,即使在转义序列 \ LineTerminator 中也是如此。

由字符字面量表示的character通常要先对字面量进行转义解释处理,就像对字面量执行String.translateEscapes 一样。

字符字面量只能表示 UTF-16 代码单元 (§3.1),即它们仅限于从 \u0000 到 \uffff 的值。补充字符必须表示为字符序列中的代理项对,或表示为整数,具体取决于它们所使用的 API。

如下是char字面量的例子:

  • 'a'
  • '%'
  • '\t'
  • '\\'
  • '\''
  • '\u03a9'
  • '\uFFFF'
  • '\177'
  • '™'

由于 Unicode 转义的处理非常早,因此为值为换行符 (LF) 的字符文本编写“\u000a”是不正确的;Unicode 转义 \u000a 在转换步骤 1 (§3.3) 中转换为实际换行符,换行符在步骤 2 (§3.4) 中转换为行终止符,因此字符文本在步骤 3 中无效。相反,应使用转义序列“\n”。同样,为值为回车符 (CR) 的字符文本编写“\u000d”也是不正确的。请改用“\r”。最后,对于包含撇号 (') 的字符文字,不能写成“\u0027”。

在 C 和 C++ 中,字符文本可能包含多个字符的表示形式,但此类字符文本的值是实现定义的。在 Java 编程语言中,字符字面量始终只表示一个字符。

3.10.5 字符串字面量

字符串字面量由用双引号括起来的零个或多个字符组成。换行符等字符可以用转义序列表示 (§3.10.7)。

StringLiteral:

        " {StringCharacter} "

StringCharacter:

        InputCharacter but not " or \

        EscapeSequence

字符串字面量总是String类型(§4.3.3)。

字符串字面量的内容是紧接在开始"之后开始,在匹配结束"之前结束的字符序列。

行终止符 (§3.4) 出现在开始"和匹配结束"之间是编译时错误。

字符 CR 和 LF 从来都不是 InputCharacter;每个都被识别为构成 LineTerminator,因此不会出现在字符串字面量中,即使在转义序列 \ LineTerminator 中也是如此。

字符串字面量表示的字符串是字符串文本的内容,每个转义序列都经过解释,就像通过对内容执行 String.translateEscapes 一样。

如下是字符串字面量的例子:

""                                         //空字符串

"\""                                       //仅包含"的字符串

"This is a string"                  //包含16个字符的字符串

"This is a " +                        //由两行字符串字面量组成的字符串

        "two-line string"

由于 Unicode 转义的处理非常早,因此为包含单个换行符 (LF) 的字符串文本编写"\u000a"是不正确的;Unicode 转义 \u000a 在转换步骤 1 (§3.3) 中转换为实际换行符,换行符在步骤 2 (§3.4) 中转换为行终止符,因此字符串文本在步骤 3 中无效。相反,应使用转义序列"\n"。同样,为包含单个回车符 (CR) 的字符串文本编写"\u000d"也是不正确的。请改用"\r"。最后,不能为包含双引号 (") 的字符串文本写入"\u0022"。

长字符串文本始终可以分解为较短的部分,并使用字符串连接运算符 + (§15.18.1) 编写为(可能用括号括起来的)表达式。

在运行时,字符串文本是对类 String (§4.3.3) 实例的引用,该实例表示字符串文本所表示的字符串。

此外,字符串字面量始终引用类 String 的同一实例。这是因为字符串字面量 - 或者更一般地说,作为常量表达式值的字符串 (§15.29) - 被“interned”以共享唯一的实例,就像通过执行方法 String.intern (§12.5) 一样。

package testPackage; 
class Test { 
    public static void main(String[] args) {
        String hello = "Hello", lo = "lo";
        System.out.println(hello == "Hello"); 
        System.out.println(Other.hello == hello); 
        System.out.println(other.Other.hello == hello); 
        System.out.println(hello == ("Hel"+"lo")); 
        System.out.println(hello == ("Hel"+lo)); 
        System.out.println(hello == ("Hel"+lo).intern());
    }

} 

class Other { static String hello = "Hello"; }

output:
true
true
true
true
false
true

此示例说明了六点:

  • 同一类和包中的字符串字面量表示对同一 String 对象 (§4.3.1) 的引用。
  • 在同一个包中的不同类的字符串字面量表示对同一个String对象的引用。
  • 不同包中不同类中的字符串文本同样表示对同一 String 对象的引用。
  • 从常量表达式 (§15.29) 连接起来的字符串在编译时计算,然后将其视为字面量。
  • 在运行时通过拼接计算的字符串是新创建的,因此是不同的。
  • 显式intern字符串的结果与具有相同内容的任何预先存在的字符串字面量的 String 对象相同。

3.10.6 文本块

文本块由零个或多个字符组成,这些字符由左分隔符和右分隔符括起来。字符可以用转义序列 (§3.10.7) 表示,但必须在字符串文本 (§3.10.5) 中用转义序列表示的换行符和双引号字符可以直接在文本块中表示。

TextBlock:

        " " " {TextBlockWhiteSpace} LineTerminator {TextBlockCharacter} " " "

TextBlockWhiteSpace:

        WhiteSpace but not LineTerminator

TextBlockCharacter:

        InputCharacter but not \

        EscapeSequence

        LineTerminator

WhiteSpace:

        the ASCII SP character, also known as "space"

        the ASCII HT character, also known as "horizontal tab"

        the ASCII FF character, also known as "form feed"

        LineTerminator

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

InputCharacter:

        UnicodeInputCharacter but not CR or LF

UnicodeInputCharacter:

        UnicodeEscape

        RawInputCharacter

UnicodeEscape:

        \ UnicodeMarker HexDigit HexDigit HexDigit HexDigit

RawInputCharacter:

        any Unicode character

文本块总是String类型的。

开始分隔符是以三个双引号字符 (""") 开头,以零个或多个空格、制表符和表单换向字符结尾,并以行终止符结尾的序列。

结束分隔符是三个双引号字符的序列。

文本块的内容是字符序列,它紧接在开始分隔符的行终止符之后,并在结束分隔符的第一个双引号之前结束。

与字符串文本 (§3.10.5) 不同,行终止符出现在文本块的内容中不是编译时错误。

当需要多行的字符串时,采用文本块的方式要比字符串的拼接可读性更高。例如,如下HTML片段的不同表示方式:

String html = "<html>\n" +
              " <body>\n" + 
              " <p>Hello, world</p>\n" + 
              " </body>\n" + 
              "</html>\n";
String html = """
              <html>
                <body>
                    <p>Hello, world</p>
                </body>
              </html>
              """;

如下是关于文本框的一些例子:

class Test {
    public static void main(String[] args) {
        // The six characters w i n t e r 
        String season = """ winter""";

        // The seven characters w i n t e r LF 
        String period = """
                        winter 
                        """;

        // The ten characters H i , SP " B o b " LF 
        String greeting = """
                            Hi, "Bob" 
                          """;

        // The eleven characters H i , LF SP " B o b " LF 
        String salutation = """
                            Hi, 
                            "Bob" 
                            """;

        // The empty string (zero length) 
        String empty = """ """;

        // The two characters " LF 
        String quote = """
                        " 
                        """;

        // The two characters \ LF 
        String backslash = """
                            \\ 
                            """;
    }
}

在文本块中允许使用转义序列 \n 和 \" 分别表示换行符和双引号字符,但通常不是必需的。例外情况是出现三个连续的双引号字符,这些字符不打算作为结束分隔符 “”“ - 在这种情况下,必须至少转义一个双引号字符,以避免被误认为结束分隔符。

在以下程序中,如果对单个双引号字符进行转义,则 story 变量的值的可读性将降低:

class Story1 {
    public static void main(String[] args) {
        String stroy = """
            "When I use a word," Humpty Dumpty said, 
            in rather a scornful tone, "it means just what I 
            choose it to mean - neither more nor less."
            "The question is," said Alice, "whether you 
            can make words mean so many different things." 
            "The question is," said Humpty Dumpty, 
            "which is to be master - that's all."
        """;
    }
}

如果修改程序以将结束分隔符放在内容的最后一行,则会发生错误,因为最后一行的前三个连续双引号字符 (§3.2) 被转换为结束分隔符 """,因此仍然存在一个杂散的双引号字符:

class Story2 {
    public static void main(String[] args) {
        String stroy = """
            "When I use a word," Humpty Dumpty said, 
            in rather a scornful tone, "it means just what I 
            choose it to mean - neither more nor less."
            "The question is," said Alice, "whether you 
            can make words mean so many different things." 
            "The question is," said Humpty Dumpty, 
            "which is to be master - that's all.""""; //错误
    }
}

可以通过转义内容中的最后一个双引号字符来避免该错误:

class Story3 {
    public static void main(String[] args) {
        String stroy = """
            "When I use a word," Humpty Dumpty said, 
            in rather a scornful tone, "it means just what I 
            choose it to mean - neither more nor less."
            "The question is," said Alice, "whether you 
            can make words mean so many different things." 
            "The question is," said Humpty Dumpty, 
            "which is to be master - that's all.\""""; //OK
    }
}

如果一个文本块旨在表示另一个文本块,则建议对嵌入的开始和结束分隔符的第一个双引号字符进行转义:

class Code {
    public static void main(String[] args) {
         String text = """ 
            The quick brown fox jumps over the lazy dog 
         """;

    String code =
        """ 
        String text = \""" 
            The quick brown fox jumps over the lazy dog 
        \"""; 
        """;
    }
}

文本块表示的字符串不是内容中字符的文字序列。相反,由文本块表示的字符串是按顺序对内容应用以下转换的结果:

  1. 行终止符规范化为 ASCII LF 字符,如下所示:
    1. 后跟 ASCII LF 字符的 ASCII CR 字符将转换为 ASCII LF 字符。
    2. 将 ASCII CR 字符转换为 ASCII LF 字符。
  2. 删除了附带的空格,就像通过对步骤 1 生成的字符执行 String.stripIndent 一样。
  3. 转义序列的解释,就像通过对步骤 2 生成的字符执行 String.translateEscapes 一样。

当此规范说文本块包含特定字符或字符序列,或者特定字符或字符序列位于文本块中时,这意味着文本块表示的字符串(与内容中的字符文本序列相反)包含字符或字符序列。

最后解释转义序列允许程序员使用 \n、\f 和 \r 进行字符串的垂直格式设置,而不会影响行终止符的规范化,并使用 \b 和 \t 进行字符串的水平格式设置,而不会影响偶然空格的删除。例如,考虑这个文本块,它提到了转义序列 \r

String html = """
              <html>\r
                  <body>\r
                       <p>Hello, world</p>\r
                  </body>\r
              </html>\r
              """;

在将行终止符归一化为 LF 之前,不会解释 \r 转义序列。使用 Unicode 转义来可视化 LF (\u000A) 和 CR (\u000D),并使用 |要可视化左边距,文本块表示的字符串为:

|<html>\u000D\u000A

|         <body>\u000D\u000A

|                 <p>Hello, world</p>\u000D\u000A

|         </body>\u000D\u000A

|</html>

在运行时,文本块是对类 String 实例的引用,该实例表示文本块所表示的字符串。

此外,文本块始终引用类 String 的同一实例。这是因为由文本块表示的字符串,或者更一般地说,作为常量表达式 (§15.29) 值的字符串被“interned”,以便共享唯一的实例,就像通过执行方法 String.intern (§12.5) 一样。

文本块可以在允许 String 类型的表达式的任何位置使用,例如在字符串连接 (§15.18.1) 中、在 String 实例上调用方法以及在带有 String 元素的注释中:

System.out.println("ab" + """
                          cde
                          """);
String cde = """
             abcde""".substring(2);
String math = """
              1+1 equals \
              """ + String.valueOf(2);

@Preconditions("""
    rate > 0 &&
    rate <= MAX_REFRESH_RATE
""")
public void setRefreshRate(int rate) { ... }

3.10.7 转义序列

在字符字面量、字符串字面量和文本块(§3.10.4、§3.10.5、§3.10.6)中,转义序列允许在不使用 Unicode 转义 (§3.3) 的情况下表示某些非图形字符,以及单引号、双引号和反斜杠字符。

EscapeSequence:

        \ b (backspace BS, Unicode \u0008)

        \ s (space SP, Unicode \u0020)

        \ t (horizontal tab HT, Unicode \u0009)

        \ n (linefeed LF, Unicode \u000a)

        \ f (form feed FF, Unicode \u000c)

        \ r (carriage return CR, Unicode \u000d)

        \ LineTerminator (line continuation, no Unicode representation)

        \ " (double quote ", Unicode \u0022)

        \ ' (single quote ', Unicode \u0027)

        \ \ (backslash \, Unicode \u005c)

        OctalEscape (octal value, Unicode \u0000 to \u00ff)

OctalEscape:

        \ OctalDigit

        \ OctalDigit OctalDigit

        \ ZeroToThree OctalDigit OctalDigit

OctalDigit:

        (one of)

        0 1 2 3 4 5 6 7

ZeroToThree:

        (one of)

        0 1 2 3

上面的 OctalDigit 生成来自 §3.10.1。提供八进制转义是为了与 C 兼容,但只能表示 Unicode 值 \u0000 到 \u00FF,因此通常首选 Unicode 转义。

如果转义序列中反斜杠后面的字符不是 LineTerminator 或 ASCII b、s、t、n、f、r、"、'、\、0、1、2、3、4、5、6 或 7,则为编译时错误。

字符文本、字符串文本或文本块内容中的转义序列通过将其 \ 和尾随字符替换为 EscapeSequence 语法中由 Unicode 转义表示的单个字符来解释。行继续转义序列没有相应的 Unicode 转义序列,因此通过将其替换为 空 来解释。

行继续转义序列可以出现在文本块中,但不能出现在字符字面量或字符串字面量中,因为两者都不允许 LineTerminator。

3.10.8 Null字面量

null 类型有一个值,即 null 引用,由 null 文本 null 表示,该文本由 ASCII 字符组成。

NullLiteral:

        null

null字面量总是null类型的。

3.11 分隔符

由 ASCII 字符组成的 12 个标记是分隔符(标点符号)。

Separator:

        (one of)

        (         ) {         } [         ]         ;         ,         .         ...         @         ::

3.12 运算符

由 ASCII 字符组成的 38 个标记是运算符。

Operator:

        (one of)

        =        >        <        !       ~        ?        :         ->

        ==        >=        <=        !=        &&        ||        ++        --

        +        -        *        /        &        |        ^        %        <<        >>        >>>

        +=         -=        *=        /=        |=        ^=        %=        <<=        >>=        >>>=

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值