Прежде всего, заявление, как
static <T extends BarIf> T newRandomBarImpl(){}
нонсенс. Он в основном говорит «независимо от того, что вызывающий заменяет T
, метод вернет его». Иными словами, вы можете написать
ArbitraryTypeExtendingBarIf x=newRandomBarImpl();
без предупреждения о компиляторе. Очевидно, что это не сработает. newRandomBarImpl()
ничего не знает о себе ArbitraryTypeExtendingBarIf
. Имя метода предполагает, что вы на самом деле хотите, чтобы выразить, что newRandomBarImpl()
может вернуть произвольное выполнение BarIf
, но это ненужное использование генериков,
BarIf newRandomBarImpl(){}
уже выражает то, что этот метод может возвратить произвольный подтип BarIf
. Фактически, поскольку BarIf
является абстрактным типом, этот метод должен вернуть подтип BarIf
, и он нигде не определен, какой он будет.
То же самое относится и к декларации
static <T extends FooIf<S>, S extends BarIf> T newFooBar(Class<S> barClass){}
Он также утверждает, что абонент может выбрать, какую реализацию FooIf
метод вернет. Правильное заявление будет
static <S extends BarIf> FooIf<S> newFooBar(Class<S> barClass){}
как метод решает, реализация FooIf
он вернется, не вызывающий.
Что касается других ваших попыток решить FooIf
, вы не можете работать таким образом, используя тип параметризованный с символом, не может это исправить с помощью отражения. Но вы можете написать общий код, используя параметр типа:
public static void main(String[] args)
{
BarIf bar = newRandomBarImpl();
performTheAction(bar.getClass(), bar);
}
static <T extends BarIf> void performTheAction(Class<T> cl, BarIf obj) {
FooIf<T> foo=newFooBar(cl);
foo.doSomething(cl.cast(obj));
}
static <S extends BarIf> FooIf<S> newFooBar(Class<S> barClass){}
static BarIf newRandomBarImpl(){}
interface FooIf<T extends BarIf> {
public void doSomething(T t);
}
interface BarIf{}
Метод performTheAction
является универсальным, другими словами, работает с неизвестным типом, выраженным в качестве параметра типа T
. Этот метод может быть вызван неизвестным типом ? extends BarIf
, как показано в методе main
.
Однако имейте в виду, что каждая ссылка на тип X
подразумевает, что упомянутый объект может иметь подтип X
, не беспокоясь об этом.
Вы можете просто использовать базовый класс BarIf
здесь, независимо от фактического подтипа BarIf
объект имеет:
BarIf bar = newRandomBarImpl();
FooIf<BarIf> foo=newFooBar(BarIf.class);
foo.doSomething(bar);
Обратите внимание, что если вы хотите использовать методы фактического типа реализации Foo
, не указанные в интерфейс, вам нужно будет нарисовать FooIf
до Foo
. Вы можете отличить FooIf<BarIf>
до Foo<BarIf>
без предупреждения, поскольку преобразование типового типа верное, если Foo<X> implements FooIf<X>
.
Однако он может не работать во время выполнения, поскольку метод newFooBar
не требуется возвращать экземпляр Foo
, а не любую другую реализацию FooIf
. Вот почему явный тип приведения является единственным правильным решением, поскольку он документирует, что есть предположение о фактическом типе времени выполнения объекта. Все остальные попытки будут генерировать по крайней мере одно предупреждение компилятора где-нибудь.
Почему вы не объявляете переменные как 'FooIf >' вместо 'Foo >'? – Blip
Потому что я хочу применить методы, которые не могут быть объявлены в FooIf, но только в Foo. Вот почему я использую общие методы в первую очередь. – Bastien
Почему вы не использовали типу? – Blip