假设我有Source<T>
一个纯T
对象生产者的通用接口。作为一个纯粹的生产者是接口契约的一部分。因此,一个合理的期望是,无论你用 aSource<Foo>
做什么,如果你有 a 也应该可以做到Source<? extends Foo>
。
现在我需要在 的正文中强制执行此限制Source
,以免有人意外T
以与该合同相矛盾的方式使用。
来自 JDK 的示例
正如@Miserable.Variable 指出的那样,ArrayList<Integer>
并不ArrayList<? extends Integer>
等同。那是因为它作为泛型类型不是协变的。或者换句话说,不是一个纯粹的生产者;具体来说,该方法消耗一个.ArrayList
ArrayList<T>
T
ArrayList
add(T)
T
但是有一些泛型类型是纯粹的生产者,比如Iterator
or 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
)或任何其他可以为我确保这一点的技术或工具?