18

I was taken aback earlier today when debugging some code to find that something like the following does not throw a compile-time exception:

 public Test () { 
     HashMap map = (HashMap) getList(); 
 }

 private List getList(){
     return new ArrayList();
 }

As you can imagine, a ClassCastException is thrown at runtime, but can someone explain why the casting of a List to a HashMap is considered legal at compile time?

akf
  • 38,619
  • 8
  • 86
  • 96

2 Answers2

29

Because conceivably getList() could be returning a subclass of HashMap which also implements List. Unlikely, yes, but possible, and therefore compilable.

skaffman
  • 398,947
  • 96
  • 818
  • 769
  • 9
    +1: An explicit cast is basically a situation where the programmer is telling the compiler "I know what I'm doing, so do it my way" - if the compiler doesn't know that you're really really wrong, it will go your way. Well, that's one way that it was explained to me. – weiji Sep 29 '09 at 22:42
  • 3
    Yeah, the compiler should complain if you replace `List` with `ArrayList`. – Tom Hawtin - tackline Sep 29 '09 at 22:42
  • @weiji: That's only true to some extent, and far less true than it was in C or C++. The java compiler will only give you so much rope, and if A cannot possibly be an instance of B, it will not compile. – skaffman Sep 29 '09 at 22:44
  • Thanks. Looking at the JLS (http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.5), it looks obvious after reading your explanation. It follows that final classes like `String` cannot be cast at compile-time, as there cannot potentially be a subclass which would implement `List`. – akf Sep 30 '09 at 01:14
17

For one thing List is an interface. There is no reason why there couldn't exist a subclass of HashMap which also implements the List interface. In this situation it would be perfectly valid.

developmentalinsanity
  • 6,109
  • 2
  • 22
  • 18