Search code examples
javagenericstype-erasure

Java static return type of method of generic class is type-erased?


Say I have a class:

public class GClass implements GInterface<Impl> {
// other code
  @Override
  public Class<SomeClass> getType() {
    return SomeClass.class
  }
}

That implements generic interface:

public interface GInterface<T extends OtherClass> {
// other code
  Class<SomeClass> getType();
}

And I then call getType():

GInterface gi = new GClass();
Class<SomeClass> type = gi.getType(); // <- gives warning

How does it make any sense that I get a warning here? The result of getType() is not generic (it's not using the generic type parameter T) but statically defined as Class<SomeClass>. Therefor the compiler should know that Class<SomeClass> type = gi.getType() is 100% safe right?

Am I missing something?

I expected the call: Class<SomeClass> type = gi.getType() to not generate any warnings.

UPDATE: I now found out it has to do with the type parameter of gi. This generates warning (my question is why?):

GInterface gi = new GClass();
Class<SomeClass> type = gi.getType(); // <- gives warning

Doesnt give warning:

GInterface<?> gi = new GClass();
Class<SomeClass> type = gi.getType(); // <- Doesnt give warning

Solution

  • GInterface gi is a raw type. The way Java works is that raw types basically put you into a "backwards compatibility mode" within the type checker, where the type works as if it did before generics were invented (that is, it's as if you're writing Java 1.4 code). In particular, the type's method signatures are completely stripped of generics in the compile-time calculations.

    That means that with GInterface gi, getType() returns a raw Class, not a Class<SomeClass>. You're then assigning that raw type to a generic type, which is where the warning comes from.

    (Note that this warning really is useful: because you're converting from a raw type to a generic type, the compiler has no way of checking that the conversion is correct. Class<FooBar> type = gi.getType() would also compile, but wouldn't work as you expect at runtime.)

    Declaring the type as GInterface<?> gi means it's not a raw type anymore, so getType()'s compile-time type is the generic'ed Class<SomeClass>.