Java递归泛型模板:... S extends Writer<E>> extends Entity<E,S> 的含义是什么?

5
有人能解释一下下面这个比较复杂的递归泛型模板使用吗?
public abstract class Data<E extends Data<E, S>,
                           S extends Writer<E>> extends Entity<E,S>

在使用递归泛型时,我们应该注意什么?这些类型之间的关系和规则将如何定义,例如ES?

如果有的话,请提供一些关于这种泛型用法的资源/链接/书籍。我知道有一本书谈到了这个问题,那就是Joshua Bloch的《Effective Java, 2nd ed》(第27项)。


如果我是老板,我会解雇写这段代码的人。这是什么鬼?一个人应该一眼就能理解。 - user467871
3个回答

3
让我们从最简单的开始。
S extends Writer<E>

任何类型为S的类必须是类型为E的类的写入器。
extends Entity<E,S>

这里只涉及继承,Data类继承自Entity类。

E extends Data<E, S>

任何用于 E 的类都必须从 Data 类继承,并使用其自身类型和与自身兼容的 writer 继承/实现 Data 的通用方法。

E 和 S 之间的关系应该如下所示:

//E = Example, S = ExampleWriter
public class ExampleWriter implements Writer<Example>{
//...
}
public class Example extends Data<Example,ExampleWriter>{
//...
}

需要记住的是:使用泛型提供一个Writer<SomeChildOfExample>或者一个Writer<SomeParentOfExample>可能会创建编译器错误,这取决于两个泛型类型中定义的通用方法。

你指定的描述关系的示例看起来不错。 - manikanta

2

Data有两个参数:E必须最终是其自身的实例,S必须能够Writer自身的实例(更具体地说,是由E指定的同一种类型的实例)。最后,Data<E,S>还可以作为通过相同ES参数化的Entity的能力/继承(即EntityData<E,S>Writer<E>)。

一个具体的实现可能会像这样:

NumericalData extends Data<NumericalData, NumWriter>,其中NumWriter实现/扩展了Writer<NumericalData>,而NumericalData也符合Entity<NumericalData, NumWriter>的标准。

编辑:

为什么要这样做?可能希望在抽象类中定义依赖参数/返回符合Data<E,S>标准的通用方法,但也希望能够返回/处理更明确的类型。例如,在Data<E,S>中,可能会有以下内容:

E doSomething(E toThis) { toThis.aDataClassMethod(); return toThis; }

这个类可以进行第一次调用,因为它知道E是一个Data<E,S>,并且返回更具体的类型,因为它知道toThis是一个E

说实话,递归泛型通常是走向过于聪明的路。它们可能很有用,但很多时候只是"漂亮",人们试图将问题弯曲成巧妙的东西,而不是相反。


0

我同意Carl的观点,递归类型往往以可用性为代价而变得“聪明”。 然而,在许多情况下,Java rtl应该采用这种惯用语法来强制执行严格的类型安全,并避免我们作为类库的猴子桶。

例如,即使是Object也应该至少是一个抽象递归类型,以强制执行严格的相等规则:

public abstract class Object<T extends Object<T>> {
  ...
  public boolean equals( o :T ) {
     ...
  }
}

在您的 equals() 实现中不再需要 instanceof 检查,更重要的是对 equals() 调用进行更好的编译时检查。

话虽如此,也许一个更合适、更简单的功能是“自身”类型...


(Note: Simplified Chinese used)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接