简体   繁体   中英

Java Class Casting Rules

    public static void main(String[] args) {
       new Redwood().go();
    }
    void go() {
       go2(new Tree(), new Redwood());
       go2((Redwood) new Tree(), new Redwood());
    }
    void go2(Tree t1, Redwood r1) {
       Redwood r2 = (Redwood)t1;
       Tree t2 = (Tree)r1;
    }
}

Given the class Redwood extends Tree, the main() method is in Redwood and Tree is an empty class with only a default constructor; the answer to this exam question is "A ClassCastException will be thrown when the code attempts to downcast a Tree to a Redwood."

I want to know why the exception is thrown and where. From my understanding you can declare Tree t1 = new Redwood() so why can't I cast a Tree to a Redwood directly?

By using a cast you're essentially telling the compiler "trust me. I'm a professional, I know what I'm doing and I know that although you can't guarantee it, I'm telling you that this tree variable is definitely going to be a redwood."

Since the tree isn't actually a redwood(it's an tree, you could do Tree tree = new Redwood(); and it'd be a redwood) the VM throws an exception at runtime because you've violated that trust (you told the compiler everything would be ok and it's not!)

The compiler is a bit smarter than just blindly accepting everything, if you try and cast objects in different inheritence hierarchies (cast a redwood to a String for example) then the compiler will throw it back at you because it knows that could never possibly work.

Because you're essentially just stopping the compiler from complaining, every time you cast it's important to check that you won't cause a ClassCastException by using instanceof in an if statement (or something to that effect.)

take reference http://www.xyzws.com/Javafaq/why-down-casting-throws-classcastexception/125

Every Redwood is a Tree . This is why Tree t2 = (Tree) r1; works.

Not every Tree is a Redwood . This is why Redwood r2 = (Redwood) t1; will not work if t1 is a Tree but not Redwood .

More formally, see JLS §5.1.6 :

Six kinds of conversions are called the narrowing reference conversions:

  • From any reference type S to any reference type T, provided that S is a proper supertype of T (§4.10).

  • An important special case is that there is a narrowing reference conversion from the class type Object to any other reference type (§4.12.4).

  • From any class type C to any non-parameterized interface type K, provided that C is not final and does not implement K.

  • From any interface type J to any non-parameterized class type C that is not final.

  • From any interface type J to any non-parameterized interface type K, provided that J is not a subinterface of K.

  • From the interface types Cloneable and java.io.Serializable to any array type T[].

  • From any array type SC[] to any array type TC[], provided that SC and TC are reference types and there is a narrowing reference conversion from SC to TC.

Such conversions require a test at run time to find out whether the actual reference value is a legitimate value of the new type. If not, then a ClassCastException is thrown.

Simply because Every Redwood is a Tree but Every Tree is not Redwood. The Compiler is smart enough to protect your program to do wrong things.

A variable of type Tree does not hold an object of type Tree ; instead, it holds either null or a reference to an object which is guaranteed to be usable as a Tree object. Likewise with a variable of type Redwood .

Because Redwood inherits from Tree , a Redwood object is guaranteed to be usable as a Tree object, and a variable of type Tree might hold a reference to such an object. If one tries to cast a variable of type Tree to a variable of type Redwood , such a cast will succeed if the variable holds null [since a variable of type Redwood can hold null ], or if the variable holds a reference to an object which is usable as a Redwood [since a variable of that type can hold any such reference], but will fail if the variable holds a reference to an object which is not usable as a Redwood [variables of type Redwood cannot hold references to such objects].

Note that if you try to cast the result of a new expression, the system will behave as though that result was stored into a temporary variable, and the cast was applied to that. Whether or not there is any way the variable could actually hold a reference to an object which is usable as a Redwood , the compiler may still behave as though the variable might or might not hold such a reference, and only discover that it doesn't when the code is executed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM