Java泛型何时需要<?扩展 T> 而不是 <T>切换是否有任何缺点?
给定以下示例(将 JUnit 与 Hamcrest 匹配器结合使用):
Map<String, Class<? extends Serializable>> expected = null;
Map<String, Class<java.util.Date>> result = null;
assertThat(result, is(expected));
这不会使用以下 JUnit 方法签名进行编译:assertThat
public static <T> void assertThat(T actual, Matcher<T> matcher)
编译器错误消息为:
Error:Error:line (102)cannot find symbol method
assertThat(java.util.Map<java.lang.String,java.lang.Class<java.util.Date>>,
org.hamcrest.Matcher<java.util.Map<java.lang.String,java.lang.Class
<? extends java.io.Serializable>>>)
但是,如果我将方法签名更改为:assertThat
public static <T> void assertThat(T result, Matcher<? extends T> matcher)
然后编译工作。
所以有三个问题:
- 为什么当前版本无法编译?虽然我模糊地理解这里的协方差问题,但如果有必要,我当然无法解释它。
- 将方法更改为 有什么缺点吗?如果您这样做,还有其他情况会破裂吗?
assertThat
Matcher<? extends T>
- 在 JUnit 中泛化该方法有什么意义吗?该类似乎不需要它,因为JUnit调用了matchs方法,该方法未使用任何泛型键入,并且看起来像是试图强制类型安全,而不执行任何操作,因为will实际上并不匹配,并且测试无论如何都会失败。不涉及不安全的操作(至少看起来是这样)。
assertThat
Matcher
Matcher
作为参考,以下是 JUnit 的实现:assertThat
public static <T> void assertThat(T actual, Matcher<T> matcher) {
assertThat("", actual, matcher);
}
public static <T> void assertThat(String reason, T actual, Matcher<T> matcher) {
if (!matcher.matches(actual)) {
Description description = new StringDescription();
description.appendText(reason);
description.appendText("\nExpected: ");
matcher.describeTo(description);
description
.appendText("\n got: ")
.appendValue(actual)
.appendText("\n");
throw new java.lang.AssertionError(description.toString());
}
}