Уже указывалось, что нет ни решения, ни хорошего обходного пути.Вот что я наконец-то сделал.Это работает только для моего особого случая, но вы можете взять это как вдохновение, если столкнетесь с подобными проблемами.(Это также объясняет, почему я столкнулся с этой проблемой)
Прежде всего, существует этот класс (показывает только соответствующий интерфейс):
class Pipe<Input, Output> {
boolean hasNext();
Input getNext();
void setNext(Output o);
}
Интерфейс Foo
на самом деле
interface Processor<Input, Output> {
process(Pipe<Input, Output> p);
}
и класс Bar
должен работать следующим образом
class JustCopyIt<Input, Output> implements Processor<Input, Output> {
process(Pipe<Input, Output> p) {
while (p.hasNext()) p.setNext(p.getNext());
}
}
Самый простой способ - привести значения следующим образом: p.setNext((Output) p.getNext())
.Но это плохо, поскольку это позволило бы создать экземпляр JustCopyIt<Integer, String>
.Вызов этого объекта может произойти по какой-то таинственной причине, но не в тот момент, когда будет допущена фактическая ошибка.
Выполнение class JustCopyIt<Type> implements Processor<Type, Type>
также не сработает, потому что тогда я не могу обработать Pipe<String, Object>
,
Итак, в конце концов я изменил интерфейс следующим образом:
interface Processor<Input, Output> {
process(Pipe<? extends Input, ? super Output> p);
}
Таким образом, JustCopyIt<List>
может обрабатывать Pipe<ArrayList, Collection>
.
Хотя это технически кажется единственным допустимым решением, оно все же плохо, потому что оно 1) работает только для этого особого случая, 2) потребовало от меня изменить интерфейс (что не всегда возможно) и 3) сделал код другогопроцессоры безобразны.
Редактировать:
Чтение ответа Китса снова вдохновило меня на другое решение:
public abstract class Bar<A, B> implements Foo<A, B> {
public static <B, A extends B> Bar<A, B> newInstance() {
return new BarImpl<B, A>();
}
private static class BarImpl<B, A extends B> extends Bar<A, B> {
// code goes here
}
}
// clean code without visible reversed parameters
Bar<Integer, Object> bar1 = Bar.newInstance();
Bar<Object, Integer> bar2 = Bar.newInstance(); // <- compile error