如何创建实现两个公共接口的许多类的实例的集合/列表(不修改这些类)?
我有两个接口 ( IfaceA, IfaceB) 和两个实现这些接口的类 (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() {}
}
我无法更改这些类的签名。
如何制作实现两个接口的类的实例列表或集合?
我试过的:
public static void main(String[] args) {
List<? extends IfaceA & IFaceB> test_1;
List<? extends IfaceA, IFaceB> test_2;
Class<? extends IfaceA, IFaceB>[] test_3;
}
都是错误的(通配符只能有一个绑定,而我不确定类型绑定是否可行)。
我知道这个可能有用:
Object[] objects = new Object[] {
new C(), new D()
};
for (Object o: objects) {
IfaceA a = (IfaceA) o;
IfaceB b = (IfaceB) o;
a.doA();
b.doB();
}
但这看起来不太对。
回答
可能的方法是创建包装类型
- 只能包装类的实例
implements IfaceA, IFaceB - 允许从包装实例上的包装实例上的两个接口调用所有方法。
它看起来像:
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();
}
}
这将让我们使用该 Wrapper 作为列表中的元素类型:
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
}
}
}
替代版本。
我们可以通过 getter 访问该元素,并直接在其上调用来自 IfaceA 和 IFaceB 接口的所有方法,而不是将方法调用委托给包装元素。
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();
}
}
}
或者,如果有人更喜欢 Java 8 风格,我们可以像这样重写上面的循环
list.stream()
.map(Wrapper::getElement)
.forEach(element -> {
element.doA();
element.doB();
});