2011-01-11 5 views
5

Kann jemand erklären, die unten, eher komplexe rekursive generische Vorlage Verwendung?Java Recursive generische Vorlage: was bedeutet das mit ... S erweitert Writer <E>> erweitert Entität <E,S>

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

Was sollten wir bei der Verwendung von rekursiven Generika beachten, wie oben. Und wie wird die Beziehung und die Regeln zwischen diesen Typen sein, hier E & S?

Falls vorhanden, geben Sie bitte einige Ressourcen/Links/Bücher über diese Art der generischen Verwendung an. Ich weiß, ein Buch darüber zu sprechen, Effective Java, 2. Aufl von Joshua Bloch (Punkt 27)

+0

Wenn ich ein Chef wäre ich denjenigen zu entlassen bin, der diesen Code geschrieben hat. Was zum Teufel ist das ? Man sollte auf den ersten Blick etwas verstehen –

Antwort

2

Data hat zwei Parameter, E, die letztlich eine Instanz von sich selbst sein muss, und S, die Writer eine Instanz der Lage sein muss von sich selbst (genauer gesagt, die gleiche Art von Instanz von sich spezifiziert durch E). Schließlich qualifiziert sich Data<E,S> auch als/erbt Fähigkeiten von Entity parametrisiert durch die gleichen E und S (d. H. Entity ist von Data<E,S> und Writer<E>).

Eine konkrete Implementierung könnte so etwas wie

NumericalData extends Data<NumericalData, NumWriter> schauen, wo NumWriter Geräte/Writer<NumericalData> und NumericalData auch als Entity<NumericalData, NumWriter> qualifiziert erstreckt.

EDIT:

Warum so etwas wie das? Man möchte vielleicht generische Methoden in der abstrakten Klasse definieren, die auf einem Argument/return basieren, das die Kriterien Data<E,S> erfüllt, aber auch in der Lage sein wollen, mit dem expliziteren Typ zurückzukehren/zu arbeiten. Zum Beispiel in Data<E,S> könnte es

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

sein Die Klasse kann den ersten Anruf tätigen, weil sie weiß, E ist ein Data<E,S>, und gibt den spezifischeren Typ, weil sie weiß toThis ist ein E.

Um ehrlich zu sein, sind rekursive Generika in der Regel der Weg zu clever. Sie können nützlich sein, aber oft sind sie einfach "ordentlich" und man versucht, das Problem um etwas Kluges zu lenken, anstatt umgekehrt.

3

Fangen wir mit dem einfachsten

beginnen
S extends Writer<E> 

Jede Klasse vom Typ S muss

extends Entity<E,S> 

Gerade Erbe hier die Daten-Klasse erweitert die Entity-Klasse ein Schriftsteller für die Klasse E sein.

E extends Data<E, S> 

Jede Klasse für E verwendet wird, muss sich von der Datenklasse erben und erbt/implementiert die generische Methoden der Daten seine eigene Art mit und einen Schriftsteller kompatibel mit sich.

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

im Auge zu behalten:

Die Beziehung zwischen E & S in etwa wie folgt sein sollte mit Generika ein Writer<SomeChildOfExample> oder eine Writer<SomeParentOfExample> Macht bereitstellt oder Compiler-Fehler möglicherweise nicht erstellen, hängt dies von dem generischen Methoden, die in beiden generischen Typen definiert sind.

+0

Das Beispiel, das Sie für die Beschreibung der Beziehung angegeben haben, sieht gut aus. – manikanta

0

Ich stimme Carl zu, dass rekursive Typen auf Kosten der Benutzerfreundlichkeit "clever" sind. Es gibt jedoch VIELE Fälle, in denen der Java-Rtl dieses Idiom verwendet haben sollte, um strenge Typsicherheit durchzusetzen und das Fass von Affen zu vermeiden, das wir als Klassenbibliothek haben.

Zum Beispiel, auch Object wahrscheinlich eine abstrakte rekursiven zumindest sein sollten strenge Regeln für die Gleichstellung durchzusetzen:

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

nicht mehr Instanceof Kontrollen in Ihrem equals() Implementierungen und, was noch wichtiger ist, besser Kompilierzeitprüfung für equals() -Aufrufe.

Das hieß, vielleicht eine geeignetere und weniger komplizierte Funktion ein „Self“ Typ ...