Es hängt davon ab , was Sie brauchen zu tun. Sie müssen den Parameter für den begrenzten Typ verwenden, wenn Sie Folgendes tun möchten:
public <T extends Shape> void addIfPretty(List<T> shapes, T shape) {
if (shape.isPretty()) {
shapes.add(shape);
}
}
Hier haben wir ein List<T> shapes
und ein T shape
, deshalb können wir sicher shapes.add(shape)
. Wenn es deklariert wurde List<? extends Shape>
, können Sie NICHT sicher add
darauf zugreifen (weil Sie möglicherweise ein List<Square>
und ein haben Circle
).
Indem wir einem Parameter mit begrenztem Typ einen Namen geben, haben wir die Möglichkeit, ihn an anderer Stelle in unserer generischen Methode zu verwenden. Diese Informationen sind natürlich nicht immer erforderlich. Wenn Sie also nicht so viel über den Typ wissen müssen (z. B. IhrendrawAll
) , ist nur ein Platzhalter ausreichend.
Auch wenn Sie nicht erneut auf den Parameter für den begrenzten Typ verweisen, ist ein Parameter für den begrenzten Typ erforderlich, wenn Sie mehrere Grenzen haben. Hier ist ein Zitat aus den Java Generics-FAQs von Angelika Langer
Was ist der Unterschied zwischen einer Wildcard-Bindung und einer Typparameter-Bindung?
Ein Platzhalter kann nur eine Grenze haben, während ein Typparameter mehrere Grenzen haben kann. Ein Platzhalter kann eine Unter- oder Obergrenze haben, während es für einen Typparameter keine Untergrenze gibt.
Platzhaltergrenzen und Typparametergrenzen werden häufig verwechselt, da beide als Grenzen bezeichnet werden und teilweise eine ähnliche Syntax aufweisen. […]
Syntax :
type parameter bound T extends Class & Interface1 & … & InterfaceN
wildcard bound
upper bound ? extends SuperType
lower bound ? super SubType
Ein Platzhalter kann nur eine Grenze haben, entweder eine untere oder eine obere Grenze. Eine Liste der Platzhaltergrenzen ist nicht zulässig.
Ein Typparameter kann im Gegensatz dazu mehrere Grenzen haben, aber es gibt keine Untergrenze für einen Typparameter.
Zitate aus Effective Java 2nd Edition, Punkt 28: Verwenden Sie begrenzte Platzhalter, um die API-Flexibilität zu erhöhen :
Verwenden Sie für maximale Flexibilität Platzhaltertypen für Eingabeparameter, die Hersteller oder Verbraucher darstellen. […] PECS steht für Producer- extends
, Consumer-super
[…]
Verwenden Sie keine Platzhaltertypen als Rückgabetypen . Anstatt Ihren Benutzern zusätzliche Flexibilität zu bieten, würden sie gezwungen, Platzhaltertypen im Clientcode zu verwenden. Bei ordnungsgemäßer Verwendung sind Platzhaltertypen für Benutzer einer Klasse nahezu unsichtbar. Sie veranlassen Methoden, die Parameter zu akzeptieren, die sie akzeptieren sollten, und diejenigen abzulehnen, die sie ablehnen sollten. Wenn der Benutzer der Klasse über Platzhaltertypen nachdenken muss, stimmt wahrscheinlich etwas mit der API der Klasse nicht .
Unter Anwendung des PECS-Prinzips können wir nun zu unserem addIfPretty
Beispiel zurückkehren und es flexibler gestalten, indem wir Folgendes schreiben:
public <T extends Shape> void addIfPretty(List<? super T> list, T shape) { … }
Jetzt können wir addIfPretty
sagen, a Circle
, zu a List<Object>
. Dies ist offensichtlich typsicher, und dennoch war unsere ursprüngliche Erklärung nicht flexibel genug, um dies zuzulassen.
Verwandte Fragen
Zusammenfassung
- Verwenden Sie Parameter / Platzhalter mit begrenztem Typ, um die Flexibilität Ihrer API zu erhöhen
- Wenn der Typ mehrere Parameter erfordert, haben Sie keine andere Wahl, als einen begrenzten Typparameter zu verwenden
- Wenn für den Typ eine Untergrenze erforderlich ist, haben Sie keine andere Wahl, als einen begrenzten Platzhalter zu verwenden
- "Produzenten" haben Obergrenzen, "Verbraucher" Untergrenzen
- Verwenden Sie bei Rückgabetypen keinen Platzhalter