Java类型通配符



我在试验泛型,然后是通配符类型。其目的是创建一个类型通用的可观察缓存,并为观察者提供delta。这开始偏离轨道的地方是,我想允许使用比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的示例类,假设它是一个仅从object扩展的简单POJO),并在必要时将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是完全合法的。notifyCChange(Object).

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

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

CCD_ 11表示作为CCD_ 13的超类型的某种未知类型的CCD_。由于obs的泛型类型可能与changes的泛型类型不完全匹配,因此notifyChange方法不适用。

有两种可能的修复方法:

  1. 将签名更改为notifyChange(ChangeHolder<? extends T> change),以便该方法适用于子类型
  2. 去掉所有地方的通配符,这样您就只有<T>

我更喜欢解决方案1,因为签名尽可能通用是个好主意。

最新更新