Frage zu Generics und Wildcards

Ion

Mitglied
Ich schaue mir jetzt schon seit längerem Java Generics und auch die Wildcards an, die man da verwenden kann aber mir ist immer noch nicht so ganz klar, wofür man Generics bei der Signatur einer Schnittstelle nimmt und was man damit aussagt und was das folgende zu bedeuten hat.
Bspw. das hier:
Java:
public <T extends IPrototype<T>> T create(T prototype) throws Exception {
    Class<T> type = (Class<T>) prototype.getClass();
    return create(type);
}

Was sagt das <T extends IPrototype<T>> aus? Das steht ja so nur im Kontext des Rückgabewertes der Methode oder bezieht sich das auch auf den Paramter T, den man der Methode übergibt?
Wird damit sichergestellt, dass man nur einen Typ zurückgeben kann, der die Schnittstelle IPrototype implementiert hat?

Und hier ist noch das andere, was ich am Anfang meinte
Java:
public interface IPrototype<T extends IPrototype<T>> {

}

Was sagt man damit aus?
Das war Teil einer Aufgabe, wo es darum ging eine Factory zu schreiben, mit der man neue Objekte vom Typen T erzeugen kann, welche das Marker Interface IPrototype implementieren.
Die zwei Aspekte sind mir ja bei dem Thema noch nicht so ganz klar. Was Kovariante und Kontravariante Listen sind und was man mit Generics erreichen will ist mir klar.
 
Solch ein Konstrukt `<A extends B<A>>` nennt sich "Recursive Type Bound" und kann dazu verwendet, "self"/"this"-Types zu implementieren. Das wird meist dazu verwendet, sicherzustellen, dass eine in einer Basisklasse implementierte Methode, welche sich ja nur auf einen Basistypen beziehen kann, - wenn auf einer Instanz einer vererbten Klasse ausgeführt - mit Typen der vererbten Klasse arbeiten kann und zur Compilezeit sichergestellt werden kann, dass es sich bei den beteiligten Typen auch wirklich um denselben Typen der konkreten Unterklasse handelt, und nicht um den Basistypen.
Siehe:
- https://www.sitepoint.com/self-types-with-javas-generics/
- https://vyazelenko.com/2012/03/02/recursive-generics-to-the-rescue/
Siehe auch die Definition von Javas java.lang.Enum Klasse und eine Erklärung dazu:
- https://stackoverflow.com/questions/211143/java-enum-definition

Tatsächlich ist das bei deinem Markerinterface aber nicht gegeben. Dieses Interface deklariert ja keine Methoden, welche mit einem self/this-Typ arbeiten wollen. Deshalb ist es eigentlich hier nicht nötig, einen recursive type bound zu verwenden. Eine Implementierung wie:
Java:
public interface IPrototype {}
public <T extends IPrototype> T create(T prototype) throws Exception {
  ...
}
hätte denselben Effekt: Diese Methode kann nur ganz exakt denselben Typ zurückliefern wie der vom als Argument verwendeten Objekt.
Es sei denn natürlich, das Ziel ist es in `create()`, etwa per Reflection den Typ des Objektes aus dem Typargument der generischen Klasse des Objektes auszulesen.
 
Zusätzlich sei noch gesagt, dass hier nirgendwo Wildcards im Spiel waren. Ein Wildcard in Java Generics ist ganz genau (und nur) das Fragezeichen `?` alleine in `<?>` oder als Teil eines Type Bounds wie etwa in `<? extends ...>` oder `<? super ...>`.
 

Neue Themen


Zurück
Oben