如何创建实现两个公共接口的许多类的实例的集合/列表(不修改这些类)?

Ben*_*min 6 java inheritance

我有两个接口 ( 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)

但这看起来不太对。

Psh*_*emo 7

可能的方法是创建包装类型

  • 只能包装类的实例 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)