Quand dois-Java génériques nécessitent <? s'étend T> au lieu de <T>, et est-il un inconvénient de commutation?

Donné l'exemple suivant (en utilisant JUnit avec Hamcrest les allumettes):

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

Cela ne compile pas avec JUnit assertThat signature de la méthode de:

public static <T> void assertThat(T actual, Matcher<T> matcher)

Le compilateur message d'erreur est:

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>>>)

Cependant, si je change le assertThat signature de la méthode d':

public static <T> void assertThat(T result, Matcher<? extends T> matcher)

Alors la compilation fonctionne.

Donc trois questions:

  1. Exactement pourquoi ne pas la version actuelle de la compilation? Bien que j'ai vaguement comprendre la covariance des questions ici, je ne peux pas l'expliquer si je devais le faire.
  2. Est-il un inconvénient dans l'évolution de la assertThat méthode pour Matcher<? extends T>? Il existe d'autres cas de rupture si vous l'avez fait?
  3. Il y a tout point à la genericizing de la assertThat méthode dans JUnit? Le Matcher classe ne semble pas à l'exiger, depuis JUnit appelle les matches de la méthode, qui n'est pas typé avec un médicament générique, et ressemble à une tentative de forcer un type de la sécurité qui permet de ne pas faire n'importe quoi, comme le Matcher sera tout simplement pas en fait de match, et que le test échoue, peu importe. Pas d'activités dangereuses impliquées (ou ce qu'il paraît).

Pour référence, voici la JUnit mise en œuvre de 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());
    }
}
InformationsquelleAutor Yishai | 2009-05-22