我在一个不相关的问题上看到了一些代码,但它让我很好奇,因为我从未在Java Generics中看到过这样的构造。创建一个可以作为类型参数本身或其自身后代的泛型类会有什么用处。这是一个例子:
abstract class A<E extends A<E>> {
abstract void foo(E x);
}
首先想到的是一个列表,它将列表作为参数。使用这段代码感觉很奇怪,你如何声明A类型的变量?递归声明!?
这甚至有用吗?如果是这样,你们中的任何人在代码中看到了吗?它是如何使用的?
修改
事实证明我的问题与this one的问题相同,只是表达方式不同,但该问题的答案也会回答我的问题。
还要感谢Curiously Recurring Template Pattern的引用,它提供了一些历史背景和对该主题的进一步解释。
这个古老的blog entry可能会给我们Java家伙找到最好的解释。
现在很难在这里选择一个正确答案,因为它们都很有用,所以我会选择最终产生最多阅读材料的那个(上面引用)
答案 0 :(得分:8)
如果没有这个,方法foo
的参数就无法绑定到E
类型。
如果您有此抽象类的实现B
,您现在可以强制执行该方法foo
还要求其参数的类型为B
。
class B extends A<B> {
void foo (B x){}
}
如果不这样做,foo
必须使用任何类A
。
我同意这种语法不够优雅。
答案 1 :(得分:3)
泛型不仅适用于像列表这样的容器。这种“扩展自身”类型参数用于让超类在方法参数和返回类型等位置引用子类,即使在编译超类时没有可用的实际特定子类。它类似于C ++中的curiously recurring template pattern。
您的示例的子类将声明为
class Foo extends A<Foo>
并且继承的foo()
方法变为
void foo(Foo x)
了解A
如何定义采用Foo
参数的方法,即使它实际上并不知道Foo
?
是的,这种事情很不寻常,但并非闻所未闻:内置的Enum类使用了类似的技巧。