incompatible types required: Class<T> found: Class<CAP#1> where T is a type variable

The following code:

public class A<T> {

    Class<T> klass;
    T instance;

    public A(T instance) {
        this.klass = instance.getClass(); // this requires an explicit cast to Class<T> to satisfy the compiler
        this.instance = instance;
    }
}

gives upon compilation:

A.java:7: error: incompatible types
             this.klass = instance.getClass();
                                           ^
required: Class<T>
found:    Class<CAP#1>
where T is a type-variable:
  T extends Object declared in class A
where CAP#1 is a fresh type-variable:
  CAP#1 extends Object from capture of ? extends Object
1 error

Why isn't the compiler satisfied that instance.getClass() will always produce Class<T> (since instance is of type T) and requires an explicit cast instead? Am I safe just adding the explicit cast:

this.klass = (Class<T>) instance.getClass();

... and thus silencing the compiler or is there room for run-time surprises? And if not, why can't the compiler figure that out?

Jon Skeet
people
quotationmark

Why isn't the compiler satisfied that instance.getClass() will always produce Class (since instance is of type T) and requires an explicit cast instead?

Consider this:

A<Object> a = new A<Object>("Foo");

Calling instance.getClass() won't return a Class<Object> - it will return a Class<String>. They're not the same thing, even though every String is an Object.

You can change the code to:

Class<? extends T> klass;

At that point it's logically safe, but it still requires a cast because Object.getClass() is just declared to return Class<? extends |T|> (as per JLS section 4.3.2):

The type of a method invocation expression of getClass is Class<? extends |T|> where T is the class or interface searched (ยง15.12.1) for getClass.

The |T| part means the type erasure of T, which in this case is just going to be Object.

Of course, the cast doesn't actually check anything at execution time, and you'll need @SuppressWarnings("unchecked") to silence the compiler completely, but at least the code would make logical sense at that point.

people

See more on this question at Stackoverflow