Передача параметризованного экземпляра класса в конструктор

Я проиграл в джунглях дженериков, пожалуйста, помогите мне :) У меня есть что-то вроде этого:

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

Насколько мне кажется, компилятор должен принять Argument поскольку он реализует RefreshableInterface.

  • Почему я получаю эту ошибку?
  • Как я могу заставить ProblematicClass работать?

ps: если у вас есть лучший заголовок для этого, пожалуйста, измените его. Я не мог справиться лучше.

Ответ 1

Проблема заключается в том, что ваш конструктор ожидает, что Class<T>, а T в вашем коде будет выведен как Argument<AnyOtherClassDescendant>.

Итак, вы должны передать Class<Argument<AnyOtherClassDescendant>>, и вы передаете Class<Argument>. Но вы не можете передать этот экземпляр Class напрямую, поскольку вы не можете использовать Argument<AnyOtherClassDescendant>.class.

Однако вы можете решить проблему, указав класс на требуемый экземпляр:

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

Обратите внимание, как вы должны придать Class<Argument> сначала Class<?>, А затем результирующий тип к Class<Argument<AnyOtherClassDescendant>>. Нет простого способа добиться этого.

Причина этого заключается в том, что существует только один экземпляр Class для всех параметризованных экземпляров родового типа, которые связаны с самим классом. Единый блок компиляции родового типа компилируется только в один файл класса. Я полагаю, это отличается от того, как C++ реализует шаблоны. Там вы получаете разные машинные коды для разных экземпляров.

Таким образом, если выполнить код, приведенный ниже, вы получите true в качестве вывода:

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

boolean isSameClassInstance = strList.getClass() == intList.getClass();
System.out.println(isSameClassInstance);