4
import java.util.Collection;


public class Test
{
    public static void main(String[] args)
    {
        Collection c = null;
        Test s = null;

        s = (Test) c;
    }
}

In the code sample above, I am casting a collection object to a Test object. (ignoring the null pointer). Test has no relationship to Collection whatsoever, yet this program will pass all compile-time checks.

I'm wondering why this is. My assumption is that interfaces are ignored because they are too complicated. They have no common super-type and each class can implement several interfaces, so the class/interface hierarchy would be too complicated to search efficiently?

Other than that reason I am stumped though. Does anyone know?!

Bogdan Vasilescu
  • 407
  • 4
  • 22
ares
  • 709
  • 6
  • 13

3 Answers3

8

"Non-final" is a keyword here. You may have another class

public class Test2 extends Test implements Collection

whose instance will end up being assigned to s making a cast perfectly legal.

ChssPly76
  • 99,456
  • 24
  • 206
  • 195
  • Ah, I see. If no subclass of Test implemented Collection, I would still have expected the downcast to fail (similar to how casts fail in a strictly class-only hierarchy if the type isn't found). Is that because it's not worth the effort? – ares Aug 05 '09 at 19:04
  • The compiler cannot make any assumptions about the class subclasses. Unless the class is marked as `final`, you can subclass it using its classfile. – notnoop Aug 05 '09 at 19:08
  • In other words, just because there is no subclass at compile-time, it doesn't mean that there cannot be one at runtime. – notnoop Aug 05 '09 at 19:09
  • 1
    No, it's because there's no way to know that no subclass of Test implemented Collection unless Test is final. Your example is very simple, but in real life I can have an extending class loaded over network / injected via AOP proxy / what have you – ChssPly76 Aug 05 '09 at 19:10
3

Because a subclass of Test can potentially be a subtype of Collection as well! The language specification is designed to be a bit flexible to permit casts that can be verified at run-time.

notnoop
  • 58,763
  • 21
  • 123
  • 144
0

We can view it from a different prospective: any non final class can be casted to ANY interface

import java.util.function.Predicate;

public class Test {
    public static void main(String[] args) {
        Predicate check;

        try {
            /*It's ok to cast to ANY interface because the Base class is not final.
              Java compiler allows it because some class may extend it 
              and implement the predicate interface. 
              So java compiler can check it only at runtime time not compile time.             
            */
            check = (Predicate)(new Base());

            /*
             Java compiler doesn’t allow it because the BaseFinal is final.
             And it means that no one can extend it and implement interface Predicate. 
             So java compiler can check it at compile time.
            */
            //check = (Predicate)(new BaseFinal()); 
        } catch (ClassCastException e) {
            System.out.println("Class Cast Exception");
        }
        check = (Predicate)(Base)(new Child());
    }    
}
final class BaseFinal {};

class Base {}

class Child extends Base implements Predicate {
    public boolean test(Object t) { return true; }
}
Dmitry.M
  • 2,833
  • 1
  • 17
  • 30