【问题标题】:Java Recursive generic template: what does this mean by ... S extends Writer<E>> extends Entity<E,S>Java递归通用模板:这是什么意思... S extends Writer<E>> extends Entity<E,S>
【发布时间】:2011-01-11 11:10:00
【问题描述】:

有人能解释一下下面相当复杂的递归通用模板用法吗?

public abstract class Data<E extends Data<E, S>,
                           S extends Writer<E>> extends Entity<E,S>

在使用递归泛型时我们应该记住什么,就像上面一样。以及这些类型之间的关系和规则如何,这里是 E & S

如果有的话,请提供一些关于这种通用用法的资源/链接/书籍。 我知道一本书在讨论这个问题,Effective Java,Joshua Bloch 的第二版(第 27 条)

【问题讨论】:

  • 如果我是老板,我会解雇编写此代码的人。这他妈到底是什么 ?乍一看应该明白一些事情

标签: java generics recursion templating


【解决方案1】:

让我们从最简单的开始

S extends Writer<E>

任何类型 S 的类都必须是类 E 的写入者

extends Entity<E,S>

这里只是继承,Data类扩展了Entity类。

E extends Data<E, S>

用于 E 的任何类本身都必须继承自 Data 类,并使用自己的类型和与其兼容的编写器继承/实现 Data 的泛型方法。

E&S之间的关系应该是这样的:

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

请记住:提供Writer&lt;SomeChildOfExample&gt;Writer&lt;SomeParentOfExample&gt; 的泛型可能会也可能不会产生编译器错误,这取决于两种泛型类型中定义的泛型方法。

【讨论】:

  • 您为描述关系指定的示例看起来不错。
【解决方案2】:

Data 有两个参数,E 最终必须是它自己的一个实例,S 必须能够Writer 一个它自己的实例(更具体地说,它指定了同一种自身的实例E)。最后,Data&lt;E,S&gt; 还限定为/继承 Entity 的功能,由相同的 ES 参数化(即,Entity 属于 Data&lt;E,S&gt;Writer&lt;E&gt;)。

具体的实现可能类似于

NumericalData extends Data&lt;NumericalData, NumWriter&gt; 其中NumWriter 实现/扩展Writer&lt;NumericalData&gt;NumericalData 也有资格作为Entity&lt;NumericalData, NumWriter&gt;

编辑:

为什么要做这样的事情?一个人可能想要在抽象类中定义泛型方法,这些方法依赖于满足Data&lt;E,S&gt; 标准的参数/返回,但也希望能够返回/使用更明确的类型。例如,在Data&lt;E,S&gt; 中,可能有

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

该类可以进行第一次调用,因为它知道EData&lt;E,S&gt;,并返回更具体的类型,因为它知道toThisE

说实话,递归泛型通常太聪明了。它们可能很有用,但很多时候它们只是“整洁”,人们试图将问题转向一些聪明的东西,而不是反过来。

【讨论】:

    【解决方案3】:

    我同意 Carl 的观点,即递归类型往往以牺牲可用性为代价“聪明”。然而,在很多情况下,Java rtl 应该使用这个习惯用法来强制执行严格的类型安全并避免我们作为类库所拥有的猴子桶。

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

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

    在您的 equals() 实现中不再检查 instanceof,更重要的是,更好地检查 equals() 调用。

    也就是说,也许更合适且不太复杂的功能是“Self”类型...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-17
      • 1970-01-01
      • 1970-01-01
      • 2012-05-07
      • 2015-05-18
      • 1970-01-01
      相关资源
      最近更新 更多