我有两个接口 ( 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() {}
}
Run Code Online (Sandbox Code Playgroud)
我无法更改这些类的签名。
如何制作实现两个接口的类的实例列表或集合?
我试过的:
public static void main(String[] args) {
List<? extends IfaceA & IFaceB> test_1;
List<? extends IfaceA, IFaceB> test_2;
Class<? extends IfaceA, IFaceB>[] test_3;
}
Run Code Online (Sandbox Code Playgroud)
都是错误的(通配符只能有一个绑定,而我不确定类型绑定是否可行)。
我知道这个可能有用:
Object[] objects = new Object[] {
new C(), new D()
};
for (Object o: objects) {
IfaceA a = (IfaceA) o;
IfaceB b = (IfaceB) o;
a.doA();
b.doB();
}
Run Code Online (Sandbox Code Playgroud)
但这看起来不太对。
可能的方法是创建包装类型
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();
}
}
Run Code Online (Sandbox Code Playgroud)
这将让我们使用该 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
}
}
}
Run Code Online (Sandbox Code Playgroud)
我们可以通过 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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
或者,如果有人更喜欢 Java 8 风格,我们可以像这样重写上面的循环
list.stream()
.map(Wrapper::getElement)
.forEach(element -> {
element.doA();
element.doB();
});
Run Code Online (Sandbox Code Playgroud)