假设我有一个通用接口(interface) Source<T>
这是T
的纯生产商对象。作为一个纯粹的生产者是接口(interface)契约的一部分。所以it is a reasonable expectation无论你能用 Source<Foo>
做什么, 如果你有 Source<? extends Foo>
也应该可以做到.
现在我需要在 Source
的正文中强制执行此限制, 这样就不会有人不小心使用了 T
以一种与该契约(Contract)相矛盾的方式。
来自 JDK 的示例
正如@Miserable.Variable 指出的那样,ArrayList<Integer>
和 ArrayList<? extends Integer>
不等价。那是因为ArrayList
作为通用类型不是协变的。或者换句话说,ArrayList<T>
不是T
的纯粹生产者;具体来说,ArrayList
方法 add(T)
消耗 T
.
但是有些泛型是纯粹的生产者,比如 Iterator
或 Iterable
. Iterator<Integer>
可以做什么你也可以用 Iterator<? extends Integer>
.没有像 ArrayList.add(T)
这样的方法在Iterator<T>
.
我只想确保我的界面 Source<T>
就像Iterator<T>
而不是喜欢 ArrayList<T>
.如果以后有人加一个T
-consuming 方法(如 add(T)
)到我的界面,我希望他们得到一个明确的错误。
一个更复杂的例子
简单地禁止 T
类型的参数出现在界面中并不是一个完整的解决方案。还应注意 T
可能用作其他泛型类型的参数。例如,Source<T>
中不应允许使用以下方法:
public void copyTo(List<T> destination);
因为偷偷摸摸的子类可能会尝试从列表中读取,所以它被认为是 T
-消费者;您不能在 Source<? extends Foo>
上调用此方法.另一方面,应该允许这个:
public void copyTo(List<? super T> destination);
(还有一条规则说 Source<T>
中的方法不能返回 List<T>
,但可以返回 List<? extends T>
。)
现在,实际的接口(interface)可以任意复杂,有很多方法,规则本身也很复杂。很容易出错。所以我想自动执行此检查。
是否有单元测试技巧、静态分析器、编译器/IDE 插件、注释处理器(例如在 @Covariant
上使用 T
注释)或任何其他技术或工具可以确保这一点?
最佳答案
这不是答案,但太长了,不适合放在评论中。
So it is a reasonable expectation that whatever you can do with a
Source<Foo>
, should be also possible to do if you have aSource<? extends Foo>
不,这不是一个合理的期望。您链接到整个 pdf,它转到 top level page所以不清楚你是如何确定这是合理的,但总的来说你不能任意替换一个 Foo<T>
用Foo<? extends T>
.敌人的例子,如果你有一个 ArrayList<Integer> a
你可以调用a.Add(Interger.valueOf(5))
但是如果 a
你不能这样做是ArrayList<? extends Integer> a
.
也不清楚什么是Consumer<T>
和 sendTo
.后者是Source<T>
中的方法吗? >?
如果没有这些澄清,恐怕他的问题是模棱两可的。
关于java - 如何确保仅协变地使用类型参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14014701/