【问题标题】:Complex Generics Combinations复杂的泛型组合
【发布时间】:2009-03-31 19:01:51
【问题描述】:

想象一个通用类 MySet,它维护一个父 MySet 实例和一个子 MySet 实例。这个想法是,父母应该能够持有 T 的超集,而孩子应该能够持有 T 的子集。因此,给定以下示例,请考虑以下问题:

class MySet<T> {

  MySet<? extends T> child; 

  void doStuff (Collection<? extends T> args) {
    child.doStuff(this, args);
  }

}

编辑:固定问题和示例代码以反映实际问题

现在,子泛型&lt;T> 可能比父级的&lt;T> 更具限制性,因此父级必须传入一个集合&lt;X>,其中&lt;X> 符合子级的&lt;T>。请记住,这个父->子链可以任意延长。有没有办法安排泛型,以便 parent.doStuff(...) 编译,即,它只能用它最严格的孩子的参数来调用?

这意味着 java 编译器将把通用信息一直向上传递到 parent->child 链,以确定 doStuff 的允许参数可能是什么,我不知道它是否具有这种能力。

是唯一的解决方案,以确保孩子不能比使用泛型的父母更严格(即 MySet&lt;T> child;而不是 MySet&lt;? extends T>)并且在代码的其他地方让孩子比父母更严格?

【问题讨论】:

  • 在 JDK 1.6.0_10 上编译得很好。
  • 嗯,我的代码中的示例可能过于简单化了。让我看看。

标签: java generics


【解决方案1】:

我可以立即对部分问题给出否定答案:

有什么办法可以安排 泛型,这样 parent.doStuff(...) 将编译,即,它只能 用它的参数调用 最受限制的孩子?

这意味着java编译器 会全部传递通用信息 父->子链向上的方式 确定允许的参数 to doStuff 可能是,我不知道 如果它有这种能力。

简单的答案是否定的,因为该链的实际扩展(和类型要求)仅在运行时才知道,到那时有关泛型的任何信息都已通过擦除丢失。

更进一步,如果你有一个检查类型而不是普通泛型,并且有一个方法可以在链中传递(最严格的)实际类型,你可以在运行时进行检查,并引发运行时错误,但绝不会是编译错误。

所以不,除非事先知道实际的最终类型(并且可能通过第二种类型 arg 指定),否则编译器将无法为您提供帮助。

您可以(并且应该做 imo)保持您刚刚编写的内容(应该可以正常编译),并传递一个可能不安全的参数。无论您是自己进行类型检查,还是让 JVM 引发 ClassCastException,这仍然是一个选择问题。

【讨论】:

  • 谢谢!回想起来,这应该很明显在编译时无法处理,但你肯定让我明白了:)
【解决方案2】:

呈现的代码似乎没有任何意义。

考虑

 MySet<String> c = ...;
 MySet<Object> p = new MySet<Object>(c);
 Collections<Integer> ints = ...;
 p.doStuff(ints);

这将调用c.doStuff(???, ints)intsCollection&lt;Integer&gt; 类型,但被调用者需要 doStuff(Collection&lt;? extends String&gt;)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-13
    • 2019-03-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多