Question

I have lost in the Jungle of Generics, please help me :) I have something like this:

public class BaseClass<TYPE> {
    public BaseClass(Class<TYPE> clazz) {};
}

public class FirstLevelClass<REFRESHABLE 
    extends RefreshableInterface> extends BaseClass<REFRESHABLE> {

    public FirstLevelClass(Class<REFRESHABLE> clazz) {
        super(clazz);
    };
}

public class Argument<T extends AnyOtherClass> 
    implements RefreshableInterface {

    public refresh() {}
}

pulbic class ProblematicClass 
    extends FirstLevelClass<Argument<AnyOtherClassDescendant>> {

    public ProblematicClass() {
        //Compiler error: Constructor 
        //FirstLevelClass<Argument<AnyOtherClassDescendant>>(Class<Argument>) is undefined
        super(Argument.class); 
    }
}

As far as I think, the compiler should accept Argument since it implements RefreshableInterface.

  • Why do I get this error?
  • How can I make the ProblematicClass working?

ps: if you have better title for this, please change it. I could not make up better.

Was it helpful?

Solution

Issue is, your constructor expects a Class<T>, and T in your code is inferred as Argument<AnyOtherClassDescendant>.

So, you should pass a Class<Argument<AnyOtherClassDescendant>>, and you're passing Class<Argument>. But you can't pass that Class instance directly, as you cannot do Argument<AnyOtherClassDescendant>.class.

You can however, solve the issue by typecasting the class to required instance:

public ProblematicClass() {
    super((Class<Argument<AnyOtherClassDescendant>>)(Class<?>)Argument.class); 
}

Note, how you've to typecast Class<Argument> first to Class<?>, and then the resultant type to Class<Argument<AnyOtherClassDescendant>>. There is no simple way to achieve that.

The reason behind this is, there is only a single Class instance for all parameterized instantiation of a generic type, that is associated with the class itself. A single compilation unit of a generic type, compiles to just a single class file. I guess this is different in how C++ implements templates. There you get different machine codes for different instantiation.

So, if you execute the below code, you'll get true as output:

List<String> strList = new ArrayList<String>();
List<Integer> intList = new ArrayList<Integer>();

boolean isSameClassInstance = strList.getClass() == intList.getClass();
System.out.println(isSameClassInstance);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top