简体   繁体   中英

Passing parameterized Class instance to the constructor

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.

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);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM