首页 > 解决方案 > 标记以 super 为界的泛型类型参数

问题描述

为了说明我相当棘手的问题,需要一些解释,所以请多多包涵。

我正在为使用管理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>接受更多 Listener的generals怎么办? Listener<? super T>准确地说。这是有道理的,因为期望的侦听器? super T也会接受T(它是逆变的)。

因此,ListenerHandle需要区分它是从中获得的和T托管的:ObservableTListener

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只能用于通配符。所以另一种选择是:

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

但是,在这种情况下,调用者将丢失返回ListenerHandle的 '? super TOlistener'相同的信息:? super TO

Observable<Number> o = ...;
Listener<Object> l = ...;

// does not work, but should (since we know that we passed a Listener<Object>)
ListenerHandle<Object, Number> h = o.addListener(l);
// works but Object is now generalized to ? super Number
ListenerHandle<? super Number, Number> h2 = o.addListener(l);

l = h2.managedListener(); // fails because ? super Number is not (necessarily) Object

所以,我需要一种方法来指定一个带有super边界的标记类型参数,以证明参数的有界泛型类型与返回类型的有界泛型类型相同。我怎么能这样做?

标签: javagenericstypes

解决方案


您可以将其设置为:而不是TL为 的类型添加通用参数:ListenerListener<? 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,我认为唯一的方法是静态方法解决方法

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会给您一个警告,但您还需要将其放在所有覆盖方法上。


推荐阅读