【问题标题】:Calling a method on a new object in Java without parentheses: order of operations violation? [closed]在不带括号的 Java 中调用新对象的方法:违反操作顺序? [关闭]
【发布时间】:2026-02-13 18:30:01
【问题描述】:

根据this table of Java operator precedence and associativity,成员访问的优先级高于new 运算符。

但是,给定一个类 myClass 和一个非静态成员函数 myFunction,以下代码行是有效的:

new myClass().myFunction();

如果.new 之前被评估,这行怎么执行?换句话说,为什么不需要括号?

(new myClass()).myFunction();

我的猜测是,由于(). 共享优先级,因此首先评估myClass(),因此编译器甚至在评估new 关键字之前就知道具有零参数的myClass 构造函数正在执行叫。但是,这似乎仍然暗示第一行应该与new (myClass().myFunction()); 相同,不是这种情况。

【问题讨论】:

  • 该表不是标准参考。你不能引用它作为证据。
  • 别把话塞进我嘴里。你知道我说了什么。您不能引用第三方网站作为 Java 中运算符优先级的证据。除非 引用或引用规范性参考,否则您也不能引用 SO 答案。在这种情况下,很明显是第 3 方站点出错了。我不知道我们为什么要讨论它。
  • @EJP 好吧,我误会了。我只是“把话放在你的嘴里”,因为我试图更好地理解你在说什么(以及在这一点上你为什么如此混蛋)。 “你不能引用它作为证据”的陈述似乎暗示它作为参考来源无效。所以你是说可以使用非规范性引用,但不能在 SO 问题和答案中引用它们?
  • 'Non-normative' 表示 '作为参考来源无效'。我没有就在你的日常工作中以某种方式使用这些资源发表任何声明,我也不会对此说三道四。我要补充的是,几十年来,在互联网及其前身中,我观察到,每当一个问题开始时“所以你在说”,答案总是“不”。
  • @EJP 奇怪的是,我经常重读这个讨论,每次都让我大吃一惊。我不知道为什么我们很难沟通,但我想知道这是否很大程度上是因为我真的不知道你所说的“引用它作为证据”是什么意思。这不是法庭;我并没有试图证明 Java 以某种方式表现(或应该表现)。我只是在努力理解我发现困惑的语言的一部分,我使用链接来解释为什么我感到困惑。

标签: java parsing operator-precedence


【解决方案1】:

我不同意从杰克的图表中得出的结论。编写语法时,其非终结符和结构旨在实现所描述语言的优先级和关联性。这就是表达式的经典 BNF 引入“项”和“因子”非终结符的原因 - 以在算术的加法优先级之前强制执行正常乘法。

所以语法中的“Primary -> new Creator”和“Expression -> Primary Selector”意味着“new Creator”的优先级高于“Primary Selector”。

在我看来,语法是 Java 运算符优先级和关联性表不正确的证据。

【讨论】:

  • 杰克的回答中你不同意的具体前提似乎是“只有当可以以两种不同的方式解析相同的词汇序列时,运算符的优先级才会起作用”。确实,有些语法在操作顺序方面可能是模棱两可的,并且可能有一个优先表除了语法规范本身。
  • 但您似乎是正确的,Java 的情况不是,因为Chapter 15 of the spec 说:“运算符之间的优先级由语法产生的层次结构管理。最低优先级运算符是 lambda 表达式 (->) 的箭头,然后是赋值运算符。”引用这句话作为证据可以改进你的答案。
  • (我意识到这句话来自规范的更新版本,因为当我问这个问题时,Java 中还没有引入 lambdas。)
【解决方案2】:

这是因为Java 语言的grammar 是如何定义的。仅当可以以两种不同的方式解析相同的词汇序列时,运算符的优先级才会起作用,但情况并非如此。

为什么?

因为分配定义在:

Primary: 
  ...
  new Creator

while 方法调用定义在:

Selector:
  . Identifier [Arguments]
  ...

这里都用到了:

Expression3: 
  ...
  Primary { Selector } { PostfixOp }

所以发生了什么

new myClass().myFunction();

被解析为

         Expression
             |
             |
    ---------+--------
    |                |
    |                |
  Primary        Selector
    |                |
    |                |
 ---+---            ...
 |     |
new   Creator 

所以没有根据优先级选择,因为Primary之前被减少了。请注意,对于像

这样的特殊情况
new OuterClass.InnerClass()

类名实际上是在 new 运算符之前解析的,并且确实有处理这种情况的规则。如果你想看,请检查语法。

【讨论】:

  • 不错的答案。感谢您的图表!
  • 很好的答案。非常感谢。
  • 最后一个例子不应该是:new OuterClass.NestedClass()吗?我认为您打算提及“静态”嵌套类。
最近更新 更多