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.
Each of the six core collection interfaces — Collection, Set, List, Map, SortedSet, and SortedMap — has one static factory method.
The implementation classes of the List interface are ArrayList, LinkedList, Stack, and Vector. ArrayList and LinkedList are widely used in Java programming.
Yes multiple classes can implement one interface irrespective of being in the same program or different. There is no such restriction. Interface only defines the common methods that should be included in the Implementation classes.
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();
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With