我正在研究 Java 前缀运算符并遇到了这种行为
i = +--j //does not give an error
i = -++j //does not give an error
i = ---j //gives an error
i = +++j //gives an error
为什么会这样?
我正在研究 Java 前缀运算符并遇到了这种行为
i = +--j //does not give an error
i = -++j //does not give an error
i = ---j //gives an error
i = +++j //gives an error
为什么会这样?
由于+
and +++
(or -
and --
) 都是左结合的,+++j
因此被评估为++(+j)
。由于++
只能应用于左值(即变量)而+j
不是左值(变量),因此会出现编译错误。
不过,您可以使用括号来解决此问题:i = +(++j);
.
编译器使用贪婪的从左到右选择标记。所以当它看到 时+--j
,最长的合法令牌序列是+
,因为+-
不是合法令牌,所以它+
作为第一个令牌。然后它查看下一个可以识别为令牌的最大事物,即--j
. 所以结果是+ --j
因为---j
它被--
视为最长的有效令牌,然后-j
是下一个有效令牌,并尝试将它们放在一起-- -j
,正如@Mureinik 指出的那样,它们是无效的。
在编译器甚至知道存在哪些运算符之前,它必须解析它们。我可以看到 3 种可能的解析---j
:
- - -j // 3 unary - operators
-- -j // predecrement -- followed by unary -
- --j // unary - followed by predecrement --
with 的情况+++j
是等价的,带有前置增量++
和一元+
替换。
为什么 Java 将其解释为--
,-
第二种情况,这是唯一在语法上无效的情况?编译器通常是贪婪的。 JLS 第 3.2 节规定:
使用以下三个词汇翻译步骤将原始 Unicode 字符流翻译成一系列标记,依次应用:
...
每一步都使用尽可能长的翻译,即使结果最终不会产生正确的程序,而另一个词汇翻译会。有一个例外:如果词法转换发生在类型上下文(第 4.11 节)中并且输入流有两个或多个连续的 > 字符后跟一个非 > 字符,那么每个 > 字符必须被转换为数值比较运算符 >.
(粗体强调我的)
编译器贪婪地看到两个-
字符并立即声明它是--
令牌,而不考虑接下来会出现第三个字符-
。
这与运算符关联性甚至运算符优先级无关,与语法解析有关。
正如@Mureinik 已经提到的那样,正确放置澄清括号将迫使编译器正确解析它。但它通过将字符分解为不同的标记来实现这一点,而不是通过改变操作的优先级。
表达式-++j
不受编译器贪婪的影响;-+
不是有效的令牌,因此它被正确解析为令牌-
后跟令牌++
,对于表达式也是如此+--j
。