// Program illustrating the subtleties of type casting interface I { void f(); } class A { public void g() { System.out.println("A.g"); } } class B extends A // implements I (but 'implements' commented out) { public void g() { System.out.println("B.g"); } // override public void f() { System.out.println("B.f"); } } class C extends A { public void h() { System.out.println("C.h"); } } public class cast { public static void main(String[] av) { A n = new B(); // n has static type A and dynamic type B A m = new C(); // m has static type A and dynamic type C n.g(); // prints B.g because of dynamic dispatch //n.f(); // compiler error! because compiler only knows n is an A object ((B)n).f(); // now ok - prints B.f ((B)m).f(); // this will compile too, because ((B)n) compiled! // this will throw runtime casting exception Object s = "abc"; // ok, because a String is an object // int len = s.length(); // compiler error. why? // how do we get the length of s? // type casting is only allowed between subclass and superclass: B x = new B(); //((C)x).h(); // compiler error - no cross-casting allowed ((C)(Object)x).h(); // 'Object' erases type info - don't use lightly // type casting to an interface is ALWAYS allowed, however: ((I)m).f(); // compiles but won't run ((I)n).f(); // This will compile because you can always cast to any // interface, but the tricky thing to understand is that this won't // run (get runtime exception), even though n is a B object that // contains a method f(). We still need to declare that class B // 'implements I' before this code can run. }//main } /* Although Java has some pecularities concerning type casting (casting to an interface is always allowed), type casting is actually a weakness of object oriented programming in general. Becasue OOP relies fundamentally on subtyping (inheritance): there's generally a discrepancy between the static superclass and the dynamic subclas, and this discrepancy results in weaker type safety at compile time. */