З огляду на наступний приклад (використовуючи JUnit з математиками Hamcrest):
Map<String, Class<? extends Serializable>> expected = null;
Map<String, Class<java.util.Date>> result = null;
assertThat(result, is(expected));
Це не компілюється з assertThat
підписом методу JUnit :
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>
? Чи є інші випадки, які б розірвалися, якби ви це зробили? - Чи є якийсь сенс до генералізації
assertThat
методу в JUnit?Matcher
Клас , здається, не вимагає, оскільки JUnit викликає метод сірників, яка не надрукований з будь-якими родовими, і просто виглядає як спроба змусити типу безпеки , який нічого не робить, так як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());
}
}