سؤال

I would expect that from the aspect of compile time as well as from the aspect of runtime it wouldn't be a problem for .getClass() to provide a correctly-typed return value.

But I must be wrong.

public class _GetClassGenerics2 {

  static class MyClass {
  }

  public static void main(String[] args) {
    MyClass myInstance = new MyClass();
    // here it works
    Class<? extends MyClass> type = myInstance.getClass();

    myMethod(myInstance);
  }

  public static <T extends MyClass> void myMethod(T instance) {
    Class<? extends T> type = instance.getClass();
// java.lang.RuntimeException: Uncompilable source code - incompatible types
//  required: java.lang.Class<? extends T>
//  found:    java.lang.Class<capture#1 of ? extends _GetClassGenerics2.MyClass>
  }

}

EDIT: It doesn't work with Class<T> and Class<? super T> either.

هل كانت مفيدة؟

المحلول

As per the Javadoc of the getClass method:

The actual result type is Class<? extends |X|> where |X| is the erasure of the static type of the expression on which getClass is called. For example, no cast is required in this code fragment

Here, the value for |X| in your code snippet is MyClass, hence instance.getClass() is assignable to only Class<? extends MyClass> or Class<?>.

The reason for this specific wording is because when you say that for this variable having type T where <T extends MyClass>, there can be multiple classes which extend MyClass and hence capable of satisfying the T extends MyClass criteria. Without runtime information there is no way of knowing which concrete implementation subclass of MyClass was passed in the method. Hence to provide a generic solution, it returns <? extends MyClass> since that would hold true for any subclass of MyClass irrespective of what class instance is passed in.

نصائح أخرى

java.lang.Class does not represent a type (use java.lang.reflect.Type for that). If T, were say ArrayList<String> then it makes no sense for there to be a Class<ArrayList<String>>.

It's worth noting that in this particular case there is no need for the method to be generic.

public static <T extends MyClass> void myMethod(T instance) {

Is equivalent to:

public static void myMethod(MyClass instance) {

Instead of

Class<? extends T> type = instance.getClass();

you need to use

Class<? extends MyClass> type = instance.getClass();

You cannot directly use the T here.

The reason is the method signature of Object.getClass() (which you are invoking). It's:

public final Class<? extends Object> getClass()

So you are trying to convert from Class<? extends Object> to Class<? extends T>, which is not allowed (because you are down-casting). It is allowed using an explicit cast:

Class<? extends T> type = (Class<? extends T>) instance.getClass();

will work (though it generates a type safety warning).

Java does not support a generic type of <this> e.g.

Object could implement

class Object {
    Class<this> getClass()
}

But there is no way for getClass() to express that it will return a type which is the class of the object. The compiler has no native understand of what this method does either.

IMHO, This behaviour should have been supported.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top