标记以super为边界的泛型类型参数

时间:2019-04-07 18:55:55

标签: java generics types

要说明我的棘手问题,需要一些解释,所以请耐心等待。

我正在为可观察模式设计简约接口,该模式使用可观察类中的管理ListenerHandles而不是removeListener(...)方法。

这是想法:

public interface ListenerHandle<T> {

    boolean isRemoved();
    void remove();

    Listener<T> managedListener();
    Observable<T> containingObservable();
}

public interface Observable<T> {

    T get();
    void set(T value);

    ListenerHandle<T> addListener(Listener<T> listener);
}

public interface Listener<T> {
    void onChange(ListenerHandle<T> handle, T value);
}

现在,这很好用。

但是,如果我想让Observable<T> 接受更一般的 {strong} {strong} Listener,该怎么办? Listener<? super T>这是有道理的,因为期望? super T的侦听器也将接受T(它是 contravariant )。

因此,ListenerHandle需要区分从其获得的T的{​​{1}}和受管理的Observable的{​​{1}}:< / p>

T

即使这些接口可以编译,我们也知道Listener

public interface ListenerHandle<TL, TO> {
    // ...

    Listener<TL> managedListener();
    Observable<TO> containingObservable();
}

public interface Observable<TO> {
    // ...

    <TL> ListenerHandle<TL, TO> addListener(Listener<TL> listener);
}

public interface Listener<TL> {
    void onChange(ListenerHandle<TL, ? extends TL> handle, TL value);
}

有点通用,因为它现在可以任何东西。但是,TL应该只能接受期望 <TL> ListenerHandle<TL, TO> addListener(Listener<TL> listener); 或其超级类型的听众:

Observable

这将不起作用,因为TO仅可用于通配符。因此,另一种选择是:

    <TL super TO> ListenerHandle<TL, TO> addListener(Listener<TL> listener);

但是,在这种情况下,调用者将丢失以下信息:返回的super的{​​{1}}和 ListenerHandle<? super TO, TO> addListener(Listener<? super TO> listener); 的{​​{1}}将相同< / i>:

ListenerHandle

因此,我需要一种方法来指定一个以 super 为边界的 labeled 类型参数,以证明该参数的有界泛型类型与返回类型的有界泛型类型。我该怎么办?

1 个答案:

答案 0 :(得分:0)

您可以将其设置为TL,而不是为类型Listener添加通用参数Listener<? super T>

public interface ListenerHandle<T> {

    boolean isRemoved();
    void remove();

    Listener<? super T> managedListener();
    Observable<T> containingObservable();
}

public interface Observable<T> {

    T get();
    void set(T value);

    ListenerHandle<T> addListener(Listener<? super T> listener);
}

public interface Listener<T> {

    <TO extends T> void onChange(ListenerHandle<TO> handle, TO value);
//  or:
//  void onChange(ListenerHandle<? extends T> handle, T value);
}

如果您确实需要将TL参数添加到ListenerHandle,我认为唯一的方法是static method workaround

public interface ListenerHandle<TL, TO extends TL> {

    boolean isRemoved();
    void remove();

    Listener<TL> managedListener();
    Observable<TO> containingObservable();
}

public interface Observable<TO> {

    TO get();
    void set(TO value);

//  @Deprecated
    ListenerHandle<?, TO> addListener(Listener<? super TO> listener); // implies ListenerHandle<? super TO, TO>

    @SuppressWarnings("unchecked")
    static <TL, TO extends TL> ListenerHandle<TL, TO> addListener(Observable<TO> observer, Listener<TL> listener) {
        return (ListenerHandle<TL, TO>) observer.addListener(listener);
    }
}

public interface Listener<TL> {

    void onChange(ListenerHandle<TL, ?> handle, TL value); // implies ListenerHandle<TL, ? extends TL>
}

您将必须记住永远不要直接调用obs.addListener(lis),而要使用Observable.addListener(obs, lis)。将其标记为@Deprecated会给您一个警告,但您也需要将其置于所有覆盖方法上。