Порядок литья Java
предположим, у меня есть следующая настройка
class A {
B foo();
}
class C extends B {
}
// later
A a = new A();
C theFoo = (C)a.foo();
мы знаем!--1--> возвращает тип B.
когда я делаю (C)a.foo(), это
- литье
aтипаCзатем пытается вызватьfoo()на нем? - вызов
foo()onaи приведение результата к типу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() метод.