【问题标题】:Java prefix and unary operators togetherJava 前缀和一元运算符一起使用
【发布时间】:2016-05-22 15:41:15
【问题描述】:

我在研究 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

为什么会这样?

【问题讨论】:

  • - --j+ ++j 是做什么的? (注意空格的位置。)
  • @ErickG.Hagstrom -(--j) 会递减 j 然后取该值的负数。 +(++j) 与使用多余的加号递增相同。另外,我现在正在考虑将i = (i += (-++i)) == i ? -(++i): +(--i); 之类的东西放在代码中的某个地方来惹人生气。

标签: java syntax-error unary-operator prefix-operator


【解决方案1】:

由于++++(或---)都是左关联的,+++j 被评估为++(+j)。由于++ 只能应用于左值(即变量)并且+j 不是左值(变量),因此会出现编译错误。

不过,您可以使用括号来解决此问题:i = +(++j);

【讨论】:

  • 虽然括号解决了这个问题,但这不是关联性;这是编译器对标记的解析。
【解决方案2】:

编译器使用贪婪的从左到右选择标记。所以当它看到+--j时,最长的合法token序列是+,因为+-不是一个合法token,所以它把+作为第一个token。然后它查看下一个可以识别为令牌的最大事物,即--j。 所以结果是+ --j

对于---j,它将-- 视为最长的有效令牌,然后将-j 视为下一个有效令牌,并尝试将它们组合为-- -j,正如@Mureinik 指出的那样,这是无效的。

【讨论】:

  • >> 除外,如List<List>>
【解决方案3】:

在编译器知道存在哪些运算符之前,它必须解析它们。我可以看到---j 的 3 种可能解析:

  • - - -j // 3 unary - operators
  • -- -j // predecrement -- followed by unary -
  • - --j // unary - followed by predecrement --

+++j 的情况是等价的,用预增量 ++ 和一元 + 替换。

为什么Java 将它解释为-- 后跟-,第二种情况,这是唯一在语法上无效的情况?编译器通常是贪婪的Section 3.2 of the JLS 状态:

使用以下三个依次应用的词汇翻译步骤将原始 Unicode 字符流翻译成标记序列:

...

每一步都使用尽可能长的翻译,即使结果最终不会产生正确的程序,而另一个词法翻译会。有一个例外:如果词法转换发生在类型上下文(第 4.11 节)中,并且输入流有两个或多个连续的 > 字符,后面跟着一个非 > 字符,那么每个 > 字符必须被转换为数值比较运算符 >.

(我的粗体强调)

编译器贪婪地看到两个- 字符并立即将其声明为-- 标记,而不考虑接下来会出现第三个-

这与运算符关联性甚至运算符优先级无关,与语法解析有关。

正如@Mureinik 已经提到的,正确放置澄清括号将迫使编译器正确解析它。但它通过将字符分解为不同的标记来实现这一点,而不是通过更改操作的优先级。

表达式-++j不受编译器贪婪的影响; -+ 不是一个有效的令牌,因此它被正确解析为令牌-,后跟令牌++,同样适用于表达式+--j

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-29
    • 1970-01-01
    • 2014-11-18
    相关资源
    最近更新 更多