Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
454 views
in Technique[技术] by (71.8m points)

Java casting order

Let's say I have the following setup

class A {
    B foo();
}

class C extends B {

}

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

We know a.foo() returns type B.

When I do (C)a.foo(), is it

  1. Casting a to type C then attempting to call foo() on it?
  2. Calling foo() on a and casting the result to type C?

I'm finding it difficult to determine, and have always just played on the side of caution with extra parenthesis (which isn't a bad idea, for readability, but now I'm curious)

This is in specific reference to ObjectInputStream.readObject() although I don't see how that would change the behavior.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

(C)a.foo() is equivalent to (C)(a.foo()), i.e. #2 in the question.

To get #1, you would have to write ((C)a).foo().

The Java language specification does not specify operator precedence in a nice, easy-to-read summary.

Appendix A of Introduction to Programming in Java by Sedgewick and Wayne has a comprehensive table of operator precedence.

Appendix B of The Java Programming Language has a table of operator precedence, but it is not as complete as Sedgewick's.

A close inspection of the grammar in the Java Language Specification can determine the relative precedences of the cast and method call expressions in question:

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

The relevant productions are bolded. We can see that a cast expression matches the production Expression3 : (Expression|Type) Expression3. The method call matches the production Expression3 : Primary {Selector} {PostfixOp} by means of the production Primary: Identifier {. Identifier }[IdentifierSuffix]. Putting this together, we see that the method call expression will be treated as a unit (an Expression3) to be acted upon by the cast.

Hmmm, the precedence chart is easier to follow... ;)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...