Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java generics: why someObject.getClass() doesn't return Class<? extends T>?

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.

like image 404
java.is.for.desktop Avatar asked Dec 16 '10 12:12

java.is.for.desktop


3 Answers

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.

like image 70
Sanjay T. Sharma Avatar answered Sep 20 '22 12:09

Sanjay T. Sharma


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.

like image 22
Peter Lawrey Avatar answered Sep 20 '22 12:09

Peter Lawrey


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) {
like image 26
Tom Hawtin - tackline Avatar answered Sep 21 '22 12:09

Tom Hawtin - tackline