给定以下示例(将JUnit与Hamcrest匹配器结合使用):
JUnit
Hamcrest
Map<String, Class<? extends Serializable>> expected = null; Map<String, Class<java.util.Date>> result = null; assertThat(result, is(expected));
这不能与以下内容的JUnit assertThat方法签名一起编译:
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方法签名更改为:
assertThat
public static <T> void assertThat(T result, Matcher<? extends T> matcher)
然后编译工作。
所以三个问题:
Matcher<? extends T>
Matcher
matches
供参考,以下是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()); } }
首先-我必须将你定向到http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html-她的工作非常出色。
基本思想是你使用
<T extends SomeClass>
当实际参数可以是SomeClass或它的任何子类型时。
SomeClass
在你的示例中
你说的是expected可以包含代表任何实现的类的Class对象Serializable。你的结果图说它只能容纳Date类对象。
expected
Class
Serializable
Date
当你在结果传递,你设置T准确Map的String给Date类对象,这不匹配Map的String,以任何的Serializable。
Map
String
要检查的一件事-确定要Class不要Date吗?一般而言,Stringto 的映射Class听起来并不是很有用(它可以保存的只是Date.class值而不是的实例Date)
至于泛化assertThat,其想法是该方法可以确保Matcher传入适合结果类型的a 。