在Java中对新对象调用方法时不使用括号:违反操作顺序?

40
根据此Java运算符优先级和结合性表,成员访问比new运算符具有更高的优先级。
但是,对于一个类myClass和一个非静态成员函数myFunction,以下代码行是有效的: new myClass().myFunction(); 如果在new之前先计算.,那为什么不需要括号就可以执行这行代码呢? (new myClass()).myFunction(); 我猜测由于().具有相同的优先级,所以先计算myClass(),因此编译器在评估new关键字之前就知道正在调用零个参数的myClass构造函数。然而,这仍然似乎意味着第一行应该与 new (myClass().myFunction()); 完全相同,但事实并非如此。

8
那张表不是规范性参考,你不能将其作为证据引用。 - user207421
3
不要替我说话,你知道我说了什么。你不能引用第三方网站作为Java运算符优先级的证据。你也不能引用SO答案,除非它引用或引述规范参考文献。在这种情况下,很明显是第三方网站错误了。我不知道为什么我们在讨论这个问题。 - user207421
1
@EJP 好的,我误解了。我只是“替你说话”,因为我试图更好地理解你在说什么(而且此时你为什么要这么粗鲁)。声明“你不能将其作为证据引用”似乎意味着它不是有效的参考来源。那么,您是否表示可以使用非规范性参考资料,但不可以在SO问题和答案中引用它们? - Kyle Strand
2
奇怪的是,我不时会重新阅读这个讨论,每次都让我感到困惑。我不确定为什么我们沟通起来如此困难,但我想知道这是否主要是因为我真的不知道你所说的“引用它作为证据”的意思。这不是法庭;我并不试图证明Java表现出(或应该表现出)某种方式。我只是在真诚地努力理解我觉得困惑的语言部分,并使用链接解释我为什么感到困惑。 - Kyle Strand
1
最后,从杰克的回答中,你可以看出问题实际上根本不是优先级的问题;我引用的优先级表似乎没有错误(虽然我不是语言专家),所以你说“在这种情况下,很明显是第三方网站错了”这个说法实际上是不正确的。 - Kyle Strand
显示剩余12条评论
2个回答

47
这是因为Java语言的文法规定。操作符的优先级只有在同一词汇序列可以用两种不同的方式解析时才会起作用,但这并不是这种情况。
为什么呢?
因为这是在分配中定义的:
Primary: 
  ...
  new Creator

while方法调用的定义在:

Selector:
  . Identifier [Arguments]
  ...

并且两者都在这里使用:

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

所以发生的情况是

new myClass().myFunction();

被解析为

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

因为Primary在之前被减少了,所以根据优先级并没有选择的余地。请注意对于特殊情况的处理方法,比如:

new OuterClass.InnerClass()

在实际使用中,类名在new运算符之前就被解析了,并且确实有规则来处理这种情况。如果您想了解这些规则,请查看语法。


非常好的回答。非常感谢。 - Gabriel Mesquita
最后一个例子不应该是 new OuterClass.NestedClass() 吗?我认为你想提到的是“静态”嵌套类。 - starriet

3
我不同意从Jack的图表得出的结论。当编写语法时,其非终结符和结构的设计旨在实现所描述语言的优先级和关联性。这就是为什么表达式的经典BNF引入了“term”和“factor”非终结符-以强制实现算术中正常的乘法优先于加法。
因此,在语法中,“Primary -> new Creator”和“Expression -> Primary Selector”的事实表明,“new Creator”处于比“Primary Selector”更高的优先级水平。
在我看来,该语法是Java运算符优先级和关联性表格不正确的证据。

你似乎不同意杰克回答中的特定前提:“只有在相同的词法序列可以被解析为两种不同的方式时,运算符的优先级才会发挥作用”。确实,一些语法可能在操作顺序上存在歧义,并且可能会有一个优先级表除了语法规范本身。 - Kyle Strand
但是看起来你是正确的,这在Java中是这种情况,因为规范的第15章说:“运算符之间的优先级由语法产生式的层次结构管理。最低优先级运算符是lambda表达式的箭头(->),其次是赋值运算符。”引用这句话作为证据可以改善你的答案。 - Kyle Strand
我意识到这句话是从新版本的规范中引用的,因为当我提出这个问题时,Java还没有引入Lambda。 - Kyle Strand

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接