• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 507
  • Last Modified:

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?
1 Solution
in which perspective you are viewing?
Try in java perpective.
Mayank SAssociate Director - Product EngineeringCommented:
>> 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
HappyEngineerAuthor Commented:
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
Mayank SAssociate Director - Product EngineeringCommented:
>> gives me a compile time exception because that's never valid

Yes there has to be an inheritance relationship between the 2 classes.
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now