次の例があるとします(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)
その後、コンパイルが機能します。
したがって、3つの質問:
- 現在のバージョンが正確にコンパイルされないのはなぜですか?ここでは共分散の問題を漠然と理解していますが、説明が必要な場合は、説明できませんでした。
assertThatメソッドをに変更することの欠点はありますMatcher<? extends T>か?あなたがそれをした場合に壊れる他のケースはありますか?assertThatJUnitでメソッドを一般化する意味はありますか?MatcherJUnitのは、何もしないタイプの安全性を強制しようとする試みのような任意の一般的な、そしてただルックスに型付けされていない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());
}
}