假设我有Source<T>一个纯T对象生产者的通用接口。作为一个纯粹的生产者是接口契约的一部分。因此,一个合理的期望是,无论你用 aSource<Foo>做什么,如果你有 a 也应该可以做到Source<? extends Foo>。
现在我需要在 的正文中强制执行此限制Source,以免有人意外T以与该合同相矛盾的方式使用。
来自 JDK 的示例
正如@Miserable.Variable 指出的那样,ArrayList<Integer>并不ArrayList<? extends Integer>等同。那是因为它作为泛型类型不是协变的。或者换句话说,不是一个纯粹的生产者;具体来说,该方法消耗一个.ArrayListArrayList<T>TArrayListadd(T) T
但是有一些泛型类型是纯粹的生产者,比如Iteratoror Iterable。无论你可以用一个做什么,Iterator<Integer>你也可以用一个Iterator<? extends Integer>。没有类似ArrayList.add(T)in 的方法Iterator<T>。
我只是想确保我的界面Source<T>是 likeIterator<T>而不是 like ArrayList<T>。如果将来有人在我的界面中添加了一个T消耗方法(如add(T)),我希望他们得到一个明确的错误。
一个更复杂的例子
简单地禁止类型参数T出现在界面中并不是一个完整的解决方案。还应该注意,它T可能被用作其他泛型类型的参数。例如,在 中不应允许以下方法Source<T>:
public void copyTo(List<T> destination);
因为偷偷摸摸的子类可能会尝试从列表中读取,所以它被认为是T-consumer;您不能在Source<? extends Foo>. 另一方面,应该允许这个:
public void copyTo(List<? super T> destination);
(还有另一条规则说方法 inSource<T>不能返回 a List<T>,但可以返回 a List<? extends T>。)
现在,实际的接口可以任意复杂,有很多方法,规则本身也很复杂。很容易犯错。所以我想自动化这个检查。
是否有单元测试技巧、静态分析器、编译器/IDE 插件、注释处理器(例如带有@Covariant注释T)或任何其他可以为我确保这一点的技术或工具?