一尘不染

Java泛型何时需要<?扩展了T>而不是<T>,切换是否有不利之处?

java

给定以下示例(将JUnitHamcrest匹配器结合使用):

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)

然后编译工作。

所以三个问题:

  1. 为什么当前版本完全不编译?尽管我在这里模糊地理解了协方差问题,但如果需要的话,我当然无法解释。
  2. assertThat方法更改为有什么缺点Matcher<? extends T>吗?如果这样做,还有其他情况会中断吗?
  3. assertThatJUnit中通用化方法有什么意义吗?该Matcher级似乎并不需要它,因为JUnit的调用matches方法,它不与任何通用的,只是看起来像键入企图迫使一个类型安全这并不做任何事情,因为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());
    }
}

阅读 583

收藏
2020-03-07

共1个答案

一尘不染

首先-我必须将你定向到http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html-她的工作非常出色。

基本思想是你使用

<T extends SomeClass>

当实际参数可以是SomeClass或它的任何子类型时。

在你的示例中

Map<String, Class<? extends Serializable>> expected = null;
Map<String, Class<java.util.Date>> result = null;
assertThat(result, is(expected));

你说的是expected可以包含代表任何实现的类的Class对象Serializable。你的结果图说它只能容纳Date类对象。

当你在结果传递,你设置T准确MapString给Date类对象,这不匹配Map的String,以任何的Serializable

要检查的一件事-确定要Class不要Date吗?一般而言,Stringto 的映射Class听起来并不是很有用(它可以保存的只是Date.class值而不是的实例Date)

至于泛化assertThat,其想法是该方法可以确保Matcher传入适合结果类型的a 。

2020-03-07