Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Recursive generic template: what does this mean by ... S extends Writer<E>> extends Entity<E,S>

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)

like image 222
manikanta Avatar asked Jan 11 '11 11:01

manikanta


2 Answers

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.

like image 70
josefx Avatar answered Nov 19 '22 14:11

josefx


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.

like image 30
Carl Avatar answered Nov 19 '22 13:11

Carl