This week's book giveaway is in the OO, Patterns, UML and Refactoring forum. We're giving away four copies of Refactoring for Software Design Smells: Managing Technical Debt and have Girish Suryanarayana, Ganesh Samarthyam & Tushar Sharma on-line! See this thread for details.
If you have two classes defined as follows: class ApBase extends Object implements Runnalbe class ApDervied extends ApBase implements Observer Given two variables created as follows: ApBase aBase = new ApBase(); ApDerived aDer = new ApDerived(); Why does this statement compile but not execute? Observer ob2 = (Observer) aBase; [This message has been edited by Willie Toma (edited December 10, 2001).] [This message has been edited by Willie Toma (edited December 10, 2001).]
ApBase doesn't implement Observer, so trying to cast it to one won't work well. It compiles because you are allowed to attempt any cast, even if the cast definatly won't work at runtime (as in this case). The compiler allows it because ApBase instance you try to cast could actually be a subclass of ApBase that does implement Observer, but of course in this case it is not a subclass. Look at this code: ApBase aBaseSubclass = new ApDerived(); ApBase aBase = new ApBase(); System.out.println(aBaseSubclass instanceof Observer); // prints "true" System.out.println(aBase instanceof Observer); // prints "false" Observer ob1 = (Observer) aBaseSubclass; // works just fine Observer ob2 = (Observer) aBase; // runtime error -- not an observer
Joined: May 11, 2001
Then why does: Runnable rn = aDer; aDer doesn't implement Runnable, but it executes?
Joined: Jul 27, 2001
ApDervied extends ApBase, so it implements and extends everything that ApBase does. Since ApBase implements Runnable, all of it's subclasses will implement Runnable. This is what object oriented programming is all about. You'll notice that this code doesn't need casting -- that's because unlike the previous situation, the upcast is gaurenteed to work. Here is an example:
(Untested code) I hope this was useful/made sense. [This message has been edited by David Garland (edited December 10, 2001).]
Originally posted by David Garland: It compiles because you are allowed to attempt any cast, even if the cast definatly won't work at runtime (as in this case).
Actually, this isn't entirely true. Consider the following code. 1. Object o = new Object(); 2. Runnable r = (Runnable) o; 3. Exception e = (Exception) r; 4. r = (Runnable) e; 5. String s = (String) r; Clearly lines 2 to 5 will not work, since an Object is not an Exception or String, nor does Object implement Runnable. The point is, the compiler objects to line 5, because the cast can never work. It accepts lines 2 through four, because they might work, sometimes. Line 2 would work if the reference o pointed to an Object that extends Object and implements Runnable. Such an object can always be refered to by an Object reference or a Runnable reference. Line 3 would work if the reference r pointed to an object of a class that extends Exception and implements Runnable. Such an object can always be refered to by an Runnable reference or an Exception reference. Line 4 would work if the reference e pointed to an object of a class that extends Exception and implements Runnable. Such an object can always be refered to by an Exception reference or a Runnable reference. Line 5 would work if the reference r pointed to an object of a class that extends String and implements Runnable. Of course, no such class is possible. String can never be extended, and String does not implement Runnable. The compiler knows this, and it won't let this statement compile. Any class that can be extended, can have subclasses that implement any interface. The compiler allows free casting between references to such classes, and references to interfaces. A reference to a 'final' class (e.g. String) cannot be cast to an interface, and vice versa, unless the class actually implements the interface. When casting a reference to an object of one class to a different class, things are a considerably stricter. Any subclass of Exception can implement any interface, but it will never be a subclass of ArrayList. Therefore, the compiler will not allow casting an ArrayList reference to Exception, or vice versa. The object reference type, and the type it's being cast to, must exist in the same object hierarchy. For example, the compiler allows you to cast a reference of type Exception to InteruptedException. If the reference is actually an AWTException, then a runtime error occurs. Bill