Java铸造订单
假设我有以下设置
class A { B foo(); } class C extends B { } // later A a = new A(); C theFoo = (C)a.foo();
我们知道a.foo()
返回类型B.
当我做(C)a.foo()
,是(C)a.foo()
- 将
a
转换为C
然后尝试调用它上面的foo()
? - 在
a
上调用foo()
并将结果转换为类型C
?
我发现很难确定,而且总是只是在谨慎的情况下使用额外的括号(这对于可读性来说并不是一个坏主意,但现在我很好奇)
这是对ObjectInputStream.readObject()
具体引用,虽然我没有看到它会如何改变行为。
(C)a.foo()
等同于(C)(a.foo())
,即问题中的#2。
要获得#1,你必须写((C)a).foo()
。
Java语言规范没有在一个简单易读的摘要中指定运算符优先级。
Sedgewick和Wayne的Java编程简介 附录A有一个全面的运算符优先级表。
Java编程语言的附录B有一个运算符优先级表,但它不像Sedgewick那样完整。
仔细检查Java语言规范中的语法可以确定所讨论的强制转换和方法调用表达式的相对优先级:
表达 : Expression1 [AssignmentOperator Expression1]] 表达式: Expression2 [Expression1Rest] Expression1Rest: ? 表达式:Expression1 表达式2: Expression3 [Expression2Rest] Expression2Rest: {InfixOp Expression3} Expression3 instanceof Type 表达式3: PrefixOp Expression3 (表达式|类型)表达式3 主 {选择器} {PostfixOp} 主: ParExpression NonWildcardTypeArguments(ExplicitGenericInvocationSuffix | this Arguments) 这[论点] 超级SuperSuffix 文字 新造物主 标识符{。 标识符} [IdentifierSuffix] BasicType {[]} .class void.class
相关的制作是粗体。 我们可以看到强制转换表达式与生产表达式3匹配Expression3 : (Expression|Type) Expression3
。 方法调用通过生产Primary: Identifier {. Identifier }[IdentifierSuffix]
匹配生产Expression3 : Primary {Selector} {PostfixOp}
Primary: Identifier {. Identifier }[IdentifierSuffix]
Primary: Identifier {. Identifier }[IdentifierSuffix]
。 把它们放在一起,我们看到方法调用表达式将被视为一个单元(一个Expression3
)来被强制转换。
嗯,优先图表更容易遵循……;)
方法调用具有比类型转换更高的运算符优先级 ,因此(C) a.foo()
将首先调用a.foo()
并将结果转换为类型C
相反, ((C) a).foo()
首先将a
转换为类型C
,然后调用其foo()
方法。