Link to home
Start Free TrialLog in
Avatar of HappyEngineer
HappyEngineer

asked on

Why is it possible to cast List<? extends Shape> to be a list of anything at all without any sort of warning?

Why does this compile?

    public class Shape {};
    public class Square extends Shape {};
   
    public void doStuff() {
        List<? extends Shape> shapes = new LinkedList();
        List<Square> squares = (List<Square>)shapes;
        List<Integer> shapeInts = (List<Integer>)shapes;
    }

Obviously, the cast to List<Square> makes sense because it could possibly be true that the list of Shape objects actually contains only Square objects. But why would the List<Integer> compile? Yes, it's not impossible that a list of <? extends Shape> could contain an Integer, but that would only be true if you compiled without generics compile time type checking.

I'm aware that there is no access to generics types at runtime (or at least it's not validated specially), but this seems like the sort of thing that can and should be handled at compile time.

Is there an option in Eclipse that would at least give a warning if the above is attempted?
Avatar of Manish
Manish
Flag of India image

in which perspective you are viewing?
Try in java perpective.
>> But why would the List<Integer> compile?

The check made at compile time is merely to assure that you are casting the right hand side with the left hand side (to avoid class cast exceptions). However, if you are deliberately casting something wrong on the RHS with something else on the LHS, then Java will proceed with compilation (because it assumes you know what you are casting with - it did its job of warning you with an error when there was no casting as the types were not matching). It will give you a class cast exception later on run time.

For example:

Object o = new Object () ;
String s = o ; // compile error - Java is smart enough to warn you with an error here

Object o = new Object () ;
String s = ( String ) o ;
// Java sees that you are specifying explicitly that the RHS be cast to String which is same as LHS, so it assumes you know what you are deliberately doing

However, when you run it, you wil get a ClassCastException
Avatar of HappyEngineer
HappyEngineer

ASKER

Yes, I'm viewing it in the java view. Karanw, if you do that and see a warning then let me know and I'll look harder through the list of warnings.

Mayankeagle, in the cast of (String)o, it's possible that's correct because you're casting an object. If I do
  Integer i = null;
  Float f = (Float)i;
then that correctly gives me a compile time exception because that's never valid. This isn't like C++ where you can cast anything to anything.
Is Shape by any chance an interface? In that case, you will get less aggressive warning as in the case of normal casts since you could have a subclass of Integer (not really possible since Integer is final) implement shape.

If Shape was an abstract class from a completely different hierarchy than Integer, then it would be obvious you can't have a class subclass both of them. But if any of the two class names are an interface, everything is possible. I agree that they could check for final classes and figure some more stuff out though.

Warning in Eclipse should show up for risky operations, unless you use @SupressWarnings
ASKER CERTIFIED SOLUTION
Avatar of Mayank S
Mayank S
Flag of India image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial