Фон
Я пытался использовать процессоры аннотаций для генерации реализаций определенных интерфейсов Factory. Эти интерфейсы выглядят следующим образом:
public interface ViewFactory<T extends View> {
<S extends Presenter<T>> T create(S presenter);
}
и
public interface PresenterFactory<T extends View> {
<S extends Presenter<T>> S create();
}
Обработчик аннотаций делает правильные действия и генерирует фабрику для каждого соответствующего класса, которая снабжена соответствующей аннотацией.
Проблема
Выход процессора аннотации следующий:
public final class TestViewImplFactory implements ViewFactory {
public final TestView create(TestPresenter presenter) {
return new TestViewImpl(presenter);
}
}
и соответствующий ему другой класс:
public final class TestPresenterImplFactory implements PresenterFactory {
public final TestPresenter create() {
return new TestPresenterImpl();
}
}
Однако TestViewImplFactory не может быть скомпилирован. Сообщение об ошибке:
"Класс 'TestViewImplFactory' должен быть объявлен как абстрактный или реализовать
абстрактный метод create (S) в 'ViewFactory' "
Java говорит, что верно следующее:
@Override
public View create(Presenter presenter) {
return new TestViewImpl(presenter);
}
, который не будет работать вообще, учитывая, что пользователь хочет знать, какой View будет возвращен, а какой Presenter требуется. Я бы ожидал, что:
- либо оба автоматически сгенерированных файла неправильны
- или оба верны
потому что они оба действительно похожи. Я ожидал, что первое будет правдой.
Что мне здесь не хватает?
Если я добавлю универсальный тип в TestViewImplFactory следующим образом:
public final class TestViewImplFactory implements ViewFactory<TestView> {
@Override
public <S extends Presenter<TestView>> TestView create(S presenter) {
return new TestViewImpl(presenter);
}
}
Возникает проблема, что параметр конструктора (который имеет тип TestPresenter) является неправильным. Изменение S на конкретный TestPresenter, опять же, сделает класс не компилируемым по той же причине, что и выше.
Итак, я наткнулся на «решение», которое можно скомпилировать.
Что в основном нужно сделать, это изменить интерфейс ViewFactory следующим образом:
public interface ViewFactory<T extends View, S extends Presenter<T>> {
T create(S presenter);
}
Таким образом, определение класса имеет тот же тип Generic, что и метод в вопросе выше.
После компиляции (на этот раз с общей спецификацией типа) результат будет выглядеть следующим образом:
public final class TestViewImplFactory implements ViewFactory<TestView, TestPresenter> {
public TestViewImplFactory() {
}
public final TestView create(TestPresenter presenter) {
return new TestViewImpl(presenter);
}
}
Это может быть скомпилировано и успешно выполнено.
Это, однако, не отвечает на первоначальный вопрос. Почему универсальный тип, явно указанный в определении типа, правильный, но унаследованные и , указанные в объявлении метода, неправильные и не компилируемые?
Конкретно: почему Java может наследовать один Generic автоматически (в PresenterFactory), а другой - нет (в ViewFactory, в методе и в объявлении типа)?