Java类型通配符

时间:2016-03-25 17:22:03

标签: java generics

(出于本文的目的,让我们留出java.util.Observable)

我正在尝试使用泛型,然后是通配符类型。目的是创建一个类型通用的可观察缓存,其中包含提供给观察者的增量。如果这开始脱轨,我想允许使用比Observable中指定的观察者更多的通用观察者,例如Observer<Object>或其他一些常见的超类。

我已经得出结论,这对我的用例来说过于复杂,但问题本身仍然困扰着我,因为我显然不明白如何正确使用类型通配符。

因此,如果我们从一个简单的观察者界面开始:

public interface Observer<T> {
    public void notifyChange(ChangeHolder<T> change);
}

关联的ChangeHolder,在完整实现中,这将更复杂,提供添加/更新/删除对象的列表,但这足以证明问题

public interface ChangeHolder<T> {
    T getChange();
}

因此,在Observer定义的情况下,我尝试实现了Observable抽象类:

public abstract class Observable<T> {
    private Set<Observer<? super T>> observers = new HashSet<>();

    public void addObserver(Observer<? super T> obs){
        observers.add(obs);
    }

    public void change(ChangeHolder<T> changes){
        for(Observer<? super T> obs : observers){
            obs.notifyChange(changes);
        }
    }
}

然后我可以通过声明类似class TreeCache extends ObservableCache<Tree>的东西来定义一些对象缓存,(从这一点开始我将使用Tree作为示例类来用作T,假设它是一个简单的POJO仅从Object扩展)并在必要时将ChangeHolder<Tree>个对象传递给TreeCache.change()。不幸的是编译器不同意:

The method notifyChange(ChangeHolder<capture#2-of ? super T>) in the type Observer<capture#2-of ? super T> is not applicable for the arguments (ChangeHolder<T>)

这是我的理解结束的地方。

没有ChangeHolder类(如果我的notifyChange方法只采用了普通的T),它的工作正常,因为将树传递给Observer.notifyChange(Object)是完全合法的。

我推断我应该能够对ChangeHolder做同样的事情 - ChangeHolder<T>应该满足notifyChange(ChangeHolder<? super T>),就像T满足notifyChange(? super T)一样,但显然我是误解了什么?

1 个答案:

答案 0 :(得分:2)

签名notifyChange(ChangeHolder<T> change)中没有通配符。因此,传递参数的泛型类型必须完全匹配 Observer实例的泛型类型。

Observer<? super T>表示某种未知类型的Observer,是T的超类型。由于obs的泛型类型可能与changes的泛型类型不完全匹配,因此notifyChange方法不适用。

有两种可能的解决方法:

  1. 将签名更改为notifyChange(ChangeHolder<? extends T> change),以便该方法适用于子类型。
  2. 摆脱各地的通配符,以便只改为<T>
  3. 我更喜欢解决方案1,因为签名尽可能通用是一个好主意。