Java 递归通用模板:... S extends Writer> 是什么意思?扩展实体

发布于 2024-10-11 09:24:50 字数 389 浏览 7 评论 0原文

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

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

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

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

Can some one explain the below, rather complex recursive generic template usage?

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

What should we keep in mind while using recursive generics, like above. And how will be the relation and rules between these types, here E & S?

If any, please provide some resource/links/books about this type of generic usage.
I know one book talking about this, Effective Java, 2nd ed by Joshua Bloch (Item 27)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

昨迟人 2024-10-18 09:24:50

让我们从最简单的开始

S extends Writer<E>

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

extends Entity<E,S>

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

E extends Data<E, S>

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

E与E之间的关系S 应该类似于以下内容:

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

要记住:使用提供 WriterWriter 的泛型可能会或可能不会创建编译器错误,这取决于两个泛型类型中定义的泛型方法。

Lets begin with the easiest

S extends Writer<E>

Any class of type S must be a writer for the class E

extends Entity<E,S>

Just inheritance here, The Data class extends the Entity class.

E extends Data<E, S>

Any class used for E must itself inherit from the Data class and inherits/implements the generic methods of Data using its own type and a writer compatible with itself.

The relation between E & S should be something like the following:

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

To keep in mind: with generics providing a Writer<SomeChildOfExample> or a Writer<SomeParentOfExample> might or might not create compiler errors, this depends on the generic methods defined in both generic types.

残龙傲雪 2024-10-18 09:24:50

Data 有两个参数,E 最终必须是其自身的实例,S 必须能够 Writer > 自身的实例(更具体地说,由 E 指定的同一类型的自身实例)。最后,Data 还限定为/继承由相同 ES 参数化的 Entity 的功能> (即 Entity 属于 DataWriter)。

具体实现可能类似于

NumericalData extends Data,其中 NumWriter 实现/扩展 WriterNumericalData 也符合 Entity 的资格。

编辑:

为什么要做这样的事情?人们可能希望在抽象类中定义通用方法,这些方法依赖于满足条件 Data 的参数/返回,但也希望能够返回/使用更显式的类型。例如,在 Data 中,可能有

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

该类可以进行第一个调用,因为它知道 E 是一个 Data;,并返回更具体的类型,因为它知道 toThisE

老实说,递归泛型通常是通往聪明之路。它们可能很有用,但很多时候它们只是“简洁”,人们试图通过一些巧妙的方法来解决问题,而不是反之亦然。

Data has two parameters, E which must ultimately be an instance of itself, and S which must be able to Writer an instance of itself (more specifically, the same kind of instance of itself specified by E). Finally, Data<E,S> also qualifies as/inherits capabilities from Entity parametrized by the same E and S (i.e., Entity is of Data<E,S> and Writer<E>).

A concrete implementation might look something like

NumericalData extends Data<NumericalData, NumWriter> where NumWriter implements/extends Writer<NumericalData> and NumericalData also qualifies as an Entity<NumericalData, NumWriter>.

EDIT:

Why do something like this? One might want to define generic methods in the abstract class that rely on an argument/return meeting the criteria Data<E,S>, but also want to be able to return/work with the more explicit type. For example, in Data<E,S>, there might be

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

The class can make the first call, because it knows E is a Data<E,S>, and return the more specific type because it knows toThis is an E.

To be honest, recursive generics are typically the road to too clever. They can be useful, but many times they're just "neat" and one tries to bend the problem around something clever rather than vice versa.

只有影子陪我不离不弃 2024-10-18 09:24:50

我同意 Carl 的观点,即递归类型往往会“聪明”,但会牺牲可用性。然而,在很多情况下,Java rtl 应该使用这种习惯来强制执行严格的类型安全,并避免我们作为类库遇到的麻烦。

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

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

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

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

I agree with Carl that recursive types tend to be "clever" at the expense of usability. However there are a LOT of cases where the Java rtl should have employed this idiom to enforce strict type safety and to avoid the barrel of monkeys we have as a class library.

For example, even Object should probably be an abstract recursive type at least to enforce strict rules for equality:

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

No more instanceof checks in your equals() implementations and, more importantly, better compile-time checking for equals() calls.

That said, perhaps a more suitable and less complicated feature would be a "Self" type...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文