Es wurde bereits darauf hingewiesen, dass es weder eine Lösung noch eine schöne Umgehung gibt. Hier ist, was ich schließlich getan habe. Es funktioniert nur in meinem speziellen Fall, aber Sie können sich davon inspirieren lassen, wenn Sie auf ähnliche Probleme stoßen. (Es erklärt auch, warum ich auf dieses Problem gestoßen bin)
Zunächst einmal gibt es diese Klasse (die nur die relevante Schnittstelle zeigt):
class Pipe<Input, Output> {
boolean hasNext();
Input getNext();
void setNext(Output o);
}
En Foo
Schnittstelle ist eigentlich
interface Processor<Input, Output> {
process(Pipe<Input, Output> p);
}
und die Klasse Bar
sollte folgendermaßen funktionieren
class JustCopyIt<Input, Output> implements Processor<Input, Output> {
process(Pipe<Input, Output> p) {
while (p.hasNext()) p.setNext(p.getNext());
}
}
Am einfachsten wäre es, die Werte wie folgt zu kodieren: p.setNext((Output) p.getNext())
. Dies ist jedoch schlecht, da es erlauben würde, eine Instanz von JustCopyIt<Integer, String>
. Der Aufruf dieses Objekts würde auf mysteriöse Weise an einem bestimmten Punkt fehlschlagen, aber nicht an dem Punkt, an dem der eigentliche Fehler gemacht wird.
Tun class JustCopyIt<Type> implements Processor<Type, Type>
würde hier auch nicht funktionieren, weil ich dann nicht in der Lage bin, eine Pipe<String, Object>
.
Also habe ich die Schnittstelle in diese geändert:
interface Processor<Input, Output> {
process(Pipe<? extends Input, ? super Output> p);
}
Auf diese Weise kann ein JustCopyIt<List>
ist in der Lage, eine Pipe<ArrayList, Collection>
.
Auch wenn dies technisch gesehen die einzig gültige Lösung zu sein scheint, ist sie dennoch schlecht, weil sie 1) nur für diesen speziellen Fall funktioniert, 2) eine Änderung der Schnittstelle erfordert (was nicht immer möglich ist) und 3) den Code der anderen Prozessoren hässlich macht.
編集する。
Die Lektüre von Keiths Antwort hat mich erneut zu einer anderen Lösung inspiriert:
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