Порядок литья Java

предположим, у меня есть следующая настройка

class A {
    B foo();
}

class C extends B {

}

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

мы знаем!--1--> возвращает тип B.

когда я делаю (C)a.foo(), это

  1. литье a типа C затем пытается вызвать foo() на нем?
  2. вызов foo() on a и приведение результата к типу C?

мне трудно определить, и всегда просто играл на стороне осторожности с дополнительными скобками (которые неплохая идея, для читаемости, но теперь мне любопытно)

это в конкретной ссылке на ObjectInputStream.readObject() хотя я не вижу, как это изменит поведение.

2 ответов


(C)a.foo() эквивалентно (C)(a.foo()), т. е. № 2 в вопрос.

чтобы получить #1, вам нужно будет написать ((C)a).foo().

спецификация языка Java не определяет приоритет оператора в приятном, удобном для чтения резюме.

Приложение A of введение в программирование на Java по Sedgewick и Wayne имеет полную таблицу приоритета оператора.

приложение Б Программирование На Java Язык имеет таблицу приоритета оператора, но она не так полна, как у Седжвика.

тщательный осмотр грамматика в спецификации языка 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

соответствующие производства выделены жирным шрифтом. Мы видим, что выражение cast соответствует production Expression3 : (Expression|Type) Expression3. Вызов метода соответствует production Expression3 : Primary {Selector} {PostfixOp} С помощью производство Primary: Identifier {. Identifier }[IdentifierSuffix]. Собрав все это воедино, мы видим, что выражение вызова метода будет рассматриваться как единица (Expression3), на который будут действовать актеры.

Хммм, диаграмма приоритета легче следовать... ;)


вызов метода имеет более высокий приоритет, чем оператор приведения типа, так что (C) a.foo() будет первый звонок a.foo() и приведите результат к типу C. В отличие от этого, ((C) a).foo() первые забросы a типа C а затем называет его foo() метод.