【问题标题】:What would be the use of accepting itself as type arguments in generics在泛型中接受自己作为类型参数有什么用
【发布时间】:2010-03-30 01:27:24
【问题描述】:

我在一个不相关的问题上看到了一些代码,但这让我很好奇,因为我从未见过 Java 泛型的这种构造。创建一个可以作为类型参数本身或其后代的泛型类有什么用。这是示例:

abstract class A<E extends A<E>> {
    abstract void foo(E x);
}

首先想到的是一个以列表为参数的列表。使用这段代码感觉很奇怪,你如何声明一个类型为 A 的变量?递归声明!?

这还有效吗?如果是这样,你们中有人在代码中看到了吗?它是如何使用的?


编辑

事实上,我的问题与this one 相同,只是措辞不同,但该问题的答案也会回答我的问题。

也感谢您对Curiously Recurring Template Pattern 的引用,它提供了一些历史背景和对该主题的进一步解释。

这个老 blog entry 可能给出了我为我们 Java 人找到的最好的全面解释。

现在很难在这里选择正确的答案,因为它们都很有帮助,所以我会选择最终产生最多阅读材料的那个(参考上文)

【问题讨论】:

  • 实际上应该是abstractg class A&lt;E extends A&lt;E&gt;&gt; {。使用A 需要一个通用参数(否则它是“原始的”,混合原始类型和熟类型是一个坏主意)。这里真正的问题是该类使用通用参数的命名约定,我觉得这非常令人困惑。
  • @Tom:谢谢,是的,在阅读了这个主题并理解了这种模式的使用之后,我意识到了错误。我已经更正了上面的代码以反映这一点。

标签: java generics


【解决方案1】:

没有这个,foo 方法的参数不能绑定到类型E

如果您有此抽象类的实现B,您现在可以强制该方法foo 还要求其参数为B 类型。

 class B extends A<B> {
      void foo (B x){}
 }

否则,foo 将不得不采用任何A

我同意这个语法不够优雅。

【讨论】:

  • "您现在可以强制方法 foo 还要求其参数为 B 类型。" foo 的参数是 B,因为 B 被声明为扩展 A&lt;B&gt;。与A的类型参数的边界无关。
【解决方案2】:

泛型不仅仅适用于列表等容器。这种“扩展自身”类型参数用于让超类在方法参数和返回类型等位置引用子类,即使在编译超类时没有实际的特定子类可用。它类似于 C++ 中的curiously recurring template pattern

您的示例的子类将被声明为

class Foo extends A<Foo>

继承的foo()方法变成了

void foo(Foo x)

了解A 如何定义一个采用Foo 参数的方法,即使它实际上并不知道Foo

是的,这种事情很不寻常,但并非闻所未闻:内置的Enum 类使用了类似的技巧。

【讨论】:

  • "继承的 foo() 方法变为 void foo(Foo x)" 只是因为类 Foo 被声明为 clads Foo extends A&lt;Foo&gt;。无论EA 中的界限如何,这都是正确的。
猜你喜欢
  • 1970-01-01
  • 2018-02-10
  • 1970-01-01
  • 2021-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-21
相关资源
最近更新 更多