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.