Порядок литья 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()
метод.