Reputation: 3448
I have two interfaces (IfaceA
, IfaceB
) and two classes implementing those interface (class C
, class D
):
interface IfaceA {
void doA();
}
interface IFaceB {
void doB();
}
class C implements IfaceA, IFaceB {
public void doA() {}
public void doB() {}
}
class D implements IfaceA, IFaceB {
public void doA() {}
public void doB() {}
}
I cannot change the signature of those classes.
How can I make a list or collection of instances of classes that implement both interfaces?
What I tried:
public static void main(String[] args) {
List<? extends IfaceA & IFaceB> test_1;
List<? extends IfaceA, IFaceB> test_2;
Class<? extends IfaceA, IFaceB>[] test_3;
}
are all wrong (a wildcard can have only one bound while I'm not sure whether it's possible with type bound).
I know this one might work:
Object[] objects = new Object[] {
new C(), new D()
};
for (Object o: objects) {
IfaceA a = (IfaceA) o;
IfaceB b = (IfaceB) o;
a.doA();
b.doB();
}
but this simply doesn't look right.
Upvotes: 6
Views: 450
Reputation: 124215
Possible way around is creating wrapper type which
implements IfaceA, IFaceB
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
}
}
}
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();
});
Upvotes: 7