Java 转换顺序

2022-09-04 01:51:18

假设我有以下设置

class A {
    B foo();
}

class C extends B {

}

// later
A a = new A();
C theFoo = (C)a.foo();

我们知道返回类型 B。a.foo()

当我这样做时,是(C)a.foo()

  1. 转换为键入然后尝试调用它?aCfoo()
  2. 调用并转换结果以键入 ?foo()aC

我发现很难确定,并且总是在谨慎方面使用额外的括号(为了可读性,这不是一个坏主意,但现在我很好奇)

这是具体的参考,尽管我不明白这将如何改变行为。ObjectInputStream.readObject()


答案 1

(C)a.foo()等价于 ,即问题中的 #2。(C)(a.foo())

要获得#1,您必须编写.((C)a).foo()

Java 语言规范没有在一个漂亮、易于阅读的摘要中指定运算符优先级。

Sedgewick 和 Wayne 的附录 A《Java 编程导论》有一个全面的运算符优先级表。

Java编程语言的附录B有一个运算符优先级表,但它不如Sedgewick的那么完整。

仔细检查 Java 语言规范中的语法可以确定所讨论的强制转换和方法调用表达式的相对优先级:

Expression:
        Expression1 [AssignmentOperator Expression1]]

Expression1:
        Expression2 [Expression1Rest]

Expression1Rest:
        ?   Expression   :   Expression1

Expression2 :
        Expression3 [Expression2Rest]

Expression2Rest:
        {InfixOp Expression3}
        Expression3 instanceof Type

Expression3:
        PrefixOp Expression3
        (   Expression | Type   )   Expression3
        Primary {Selector} {PostfixOp}

Primary:
        ParExpression
        NonWildcardTypeArguments (ExplicitGenericInvocationSuffix | this Arguments)
        this [Arguments]
        super SuperSuffix
        Literal
        new Creator
        Identifier { . Identifier }[ IdentifierSuffix]
        BasicType {[]} .class
        void.class

相关作品加粗。我们可以看到,强制转换表达式与生产相匹配。方法调用通过生产来匹配生产。综上所述,我们看到方法调用表达式将被视为一个单元(a),由强制转换来操作。Expression3 : (Expression|Type) Expression3Expression3 : Primary {Selector} {PostfixOp}Primary: Identifier {. Identifier }[IdentifierSuffix]Expression3

嗯,优先级图表更容易遵循... ;)


答案 2

方法调用的运算符优先级高于类型强制转换,因此将首先调用并将结果强制转换为类型 。相反,首先强制转换为类型,然后调用其方法。(C) a.foo()a.foo()C((C) a).foo()aCfoo()