Java泛型何时需要&lt ;?延伸T>而不是< T>并有切换的任何缺点?

编程入门 行业动态 更新时间:2024-10-12 14:18:33
本文介绍了Java泛型何时需要&lt ;?延伸T>而不是< T>并有切换的任何缺点?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

映射< String,Class< ;?????????????????????????????????????????????????????????????扩展Serializable>>预期=空; Map< String,Class< java.util.Date>> result = null; assertThat(result,is(expected));

这不会使用JUnit assertThat 方法签名:

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

编译器错误信息是:

错误:错误:行(102)找不到符号方法 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 <?如果我改变 assertThat 方法签名为:

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

然后编译工作。 p>

所以有三个问题:

  • 为什么现在的版本不能编译?尽管我隐约了解这里的协变问题,但我肯定无法解释它。
  • 更改 assertThat有什么不利之处方法到匹配器<?扩展T> ?有没有其他的情况下,如果你这样做会破坏?
  • 是否有任何指向JUnit中的 assertThat 方法的泛化? 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 = new StringDescription(); description.appendText(reason); description.appendText(\\\Expected:); matcher.describeTo(description); 描述 .appendText(\\\ got:) .appendValue(actual) .appendText(\\\); 抛出新的java.lang.AssertionError(description.toString()); } }

    解决方案

    - 我必须引导您访问 www.angelikalanger/GenericsFAQ/JavaGenericsFAQ.html - 她做了一件了不起的工作。

    基本想法是,您使用

    < T extends SomeClass>

    当实际参数可以是 SomeClass 或

    在你的例子中,

    Map< / p>字符串,类<?扩展Serializable>>预期=空; Map< String,Class< java.util.Date>> result = null; assertThat(result,is(expected));

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

    当你传入结果时, T 到 Map 字符串到 Date 类对象,它与 Map 的 String 不匹配可序列化。

    要检查的一件事 - 您确定要使用 Class< Date> ; 而不是日期?一般来说, String 到 Class 对于泛化 assertThat ,想法是该方法可以确保符合结果类型的 Matcher 被传递in。

    Given the following example (using JUnit with Hamcrest matchers):

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

    This does not compile with the JUnit assertThat method signature of:

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

    The compiler error message is:

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

    However, if I change the assertThat method signature to:

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

    Then the compilation works.

    So three questions:

  • Why exactly doesn't the current version compile? Although I vaguely understand the covariance issues here, I certainly couldn't explain it if I had to.
  • Is there any downside in changing the assertThat method to Matcher<? extends T>? Are there other cases that would break if you did that?
  • Is there any point to the genericizing of the assertThat method in JUnit? The Matcher class doesn't seem to require it, since JUnit calls the matches method, which is not typed with any generic, and just looks like an attempt to force a type safety which doesn't do anything, as the Matcher will just not in fact match, and the test will fail regardless. No unsafe operations involved (or so it seems).
  • For reference, here is the JUnit implementation of 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()); } }

    解决方案

    First - I have to direct you to www.angelikalanger/GenericsFAQ/JavaGenericsFAQ.html -- she does an amazing job.

    The basic idea is that you use

    <T extends SomeClass>

    when the actual parameter can be SomeClass or any subtype of it.

    In your example,

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

    You're saying that expected can contain Class objects that represent any class that implements Serializable. Your result map says it can only hold Date class objects.

    When you pass in result, you're setting T to exactly Map of String to Date class objects, which doesn't match Map of String to anything that's Serializable.

    One thing to check -- are you sure you want Class<Date> and not Date? A map of String to Class<Date> doesn't sound terribly useful in general (all it can hold is Date.class as values rather than instances of Date)

    As for genericizing assertThat, the idea is that the method can ensure that a Matcher that fits the result type is passed in.

    更多推荐

    Java泛型何时需要&lt ;?延伸T&gt;而不是&lt; T&gt;并有切换的任何缺点?

    本文发布于:2023-11-02 17:00:14,感谢您对本站的认可!
    版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
    本文标签:并有   而不是   缺点   amp   Java

    发布评论

    评论列表 (有 0 条评论)
    草根站长

    >www.elefans.com

    编程频道|电子爱好者 - 技术资讯及电子产品介绍!