Possible way around is creating wrapper type which
- can only wrap instances of classes which
implements IfaceA, IFaceB
- allows calling all methods from both interfaces on wrapped instance on wrapped instance.
It can look like:
class Wrapper<T extends IfaceA & IFaceB> implements IfaceA, IFaceB {
private final T element;
public Wrapper(T element) {
this.element = element;
}
@Override
public void doA() {
element.doA();
}
@Override
public void doB() {
element.doB();
}
}
This will let us use that Wrapper as type of elements in the List:
class Demo {
public static void main(String[] args) {
//Wrapper<?> can represent both Wrapper<C> and Wrapper<D>
List<Wrapper<?>> list = new ArrayList<>();
list.add(new Wrapper<>(new C()));
list.add(new Wrapper<>(new D()));
for (Wrapper<?> wrapper : list){
wrapper.doA(); //both calls compile fine
wrapper.doB(); //both calls compile fine
}
}
}
Alternative version.
Instead of delegating method calls to wrapped element we can access that element via getter and call all methods from IfaceA & IFaceB interfaces directly on it.
class Wrapper<T extends IfaceA & IFaceB> {
private final T element;
public Wrapper(T element) {
this.element = element;
}
public T getElement() {
return element;
}
}
public class Demo {
public static void main(String[] args) {
List<Wrapper<?>> list = new ArrayList<>();
list.add(new Wrapper<>(new C()));
list.add(new Wrapper<>(new D()));
for (Wrapper<?> wrapper : list){
//here `var` represents "some" subtype of both IfaceA & IFaceB
var element = wrapper.getElement();
// so following is legal
element.doA();
element.doB();
}
}
}
OR if someone prefers Java 8 style we can rewrite above loop like
list.stream()
.map(Wrapper::getElement)
.forEach(element -> {
element.doA();
element.doB();
});
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…