7

The foo method in following example gives us a warning, while bar not?

public class X {

    static class Y {}
    static class Z extends Y {}

    Y y = new Y();

    <T extends Y> T foo() {
        return (T) y; // warning - Unchecked cast from X.Y to T
    }

    Z bar() {
        return (Z) y; // compiles fine
    }

}
sp00m
  • 47,968
  • 31
  • 142
  • 252
gudge
  • 1,053
  • 4
  • 18
  • 33
  • 5
    How much do you know about type erasure? See http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#Type Erasure – Jon Skeet Apr 28 '14 at 11:57
  • 1
    I think it is clear, that `foo()` should give a warning. You are casting the object `y` to some unknown superclass `T` of `Y`. I am also very interested why `bar()` does not. I guess the compiler is able to see that casting `Y` to `Z` is not causing problems, as the definition of `Z` is available. – SebastianH Apr 28 '14 at 12:12
  • 2
    @SebastianH: I don't think it is a problem. – gudge Apr 28 '14 at 12:26
  • @Pshemo: Thanks. This looks much better. Two examples compressed into one. Will remember the formatting when asking questions next time. – gudge Apr 28 '14 at 12:28
  • @gudge What I meant was that the cast `(Z) y` will fail. But that has nothing to do with compiling. – SebastianH Apr 28 '14 at 12:36

2 Answers2

1

The type T is erased down to Y at compile time, this how generics work in Java. Thus when the cast is performed at run time the type of T is not available, it is just an Y in the byte code.

bar() compiles fine as all the type information is available (the cast will fail). But foo() lacks this type information and cannot fail, potentially (or certainly, in this case) rendering the type signature of the method incorrect and becoming a source of bugs in the program.

To do this safely you need to pass the class itself to the method.

<T extends Y> T foo(Class<T> cls) {
    return cls.cast(y); //No type warning. Will throw an error when cast fails.
}
ggovan
  • 1,907
  • 18
  • 21
0

Because T its a type tag and Z its a class name. return (Z) y; its correct type casting, but return (T) y; - casting to unknown type in runtime. JVM nothing known about type tags in runtime (see this tutorial section). In absolutely short, return (T) y; almost equivalently return (Object) y;, it is unchecked cast from X.Y to Object. Also see about downcasting in Java for return (Z) y; explanation.

Community
  • 1
  • 1
injecto
  • 829
  • 1
  • 10
  • 23
  • 2
    "*`return (T) y;` almost equivalently `return (Object) y;`*" actually since `` it is equivalent in bytecode to `return (Y) y;`. – Pshemo Apr 28 '14 at 12:37