To zależy od tego, co musisz zrobić. Musisz użyć parametru typu bounded, jeśli chcesz zrobić coś takiego:
public <T extends Shape> void addIfPretty(List<T> shapes, T shape) {
if (shape.isPretty()) {
shapes.add(shape);
}
}
Tutaj mamy a List<T> shapes
i T shape
, dlatego możemy bezpiecznie shapes.add(shape)
. Jeśli zostało zadeklarowane List<? extends Shape>
, NIE możesz bezpiecznie add
do niego wejść (ponieważ możesz mieć a List<Square>
i Circle
).
Tak więc nadając nazwę ograniczonemu parametrowi typu, mamy możliwość użycia go w innym miejscu naszej metody ogólnej. Oczywiście ta informacja nie zawsze jest wymagana, więc jeśli nie musisz wiedzieć zbyt wiele o typie (np. Twój drawAll
), wystarczy tylko symbol wieloznaczny.
Nawet jeśli nie odwołujesz się ponownie do parametru typu ograniczonego, parametr typu ograniczonego jest nadal wymagany, jeśli masz wiele granic. Oto cytat z często zadawanych pytań dotyczących generycznych programów Java Angeliki Langer
Jaka jest różnica między powiązaniem z symbolem wieloznacznym a powiązaniem z parametrem typu?
Symbol wieloznaczny może mieć tylko jedno ograniczenie, podczas gdy parametr typu może mieć kilka ograniczeń. Symbol wieloznaczny może mieć dolną lub górną granicę, podczas gdy nie ma czegoś takiego jak dolna granica dla parametru typu.
Granice symboli wieloznacznych i granice parametrów typu są często mylone, ponieważ oba nazywane są granicami i mają po części podobną składnię. […]
Składnia :
type parameter bound T extends Class & Interface1 & … & InterfaceN
wildcard bound
upper bound ? extends SuperType
lower bound ? super SubType
Symbol wieloznaczny może mieć tylko jedną granicę, dolną lub górną. Lista granic symboli wieloznacznych jest niedozwolona.
W przeciwieństwie do parametru typu może mieć kilka granic, ale nie ma czegoś takiego jak dolna granica dla parametru typu.
Cytaty z Effective Java 2nd Edition, pozycja 28: Użyj ograniczonych symboli wieloznacznych, aby zwiększyć elastyczność interfejsu API :
Aby uzyskać maksymalną elastyczność, używaj symboli wieloznacznych w parametrach wejściowych, które reprezentują producentów lub konsumentów. […] PECS oznacza producenta extends
, konsumenta super
[…]
Nie używaj symboli wieloznacznych jako typów zwracanych . Zamiast zapewnić użytkownikom dodatkową elastyczność, zmusiłoby ich to do używania symboli wieloznacznych w kodzie klienta. Prawidłowo używane typy symboli wieloznacznych są prawie niewidoczne dla użytkowników klasy. Powodują, że metody akceptują parametry, które powinny zaakceptować, i odrzucają te, które powinny odrzucić. Jeśli użytkownik klasy musi pomyśleć o typach symboli wieloznacznych, prawdopodobnie jest coś nie tak z interfejsem API klasy .
Stosując zasadę PECS, możemy teraz wrócić do naszego addIfPretty
przykładu i uczynić go bardziej elastycznym, pisząc:
public <T extends Shape> void addIfPretty(List<? super T> list, T shape) { … }
Teraz możemy addIfPretty
powiedzieć a Circle
do a List<Object>
. Jest to oczywiście bezpieczne dla komputera, a jednak nasza pierwotna deklaracja nie była wystarczająco elastyczna, aby na to pozwolić.
Powiązane pytania
Podsumowanie
- Używaj ograniczonych parametrów typu / symboli wieloznacznych, zwiększają one elastyczność interfejsu API
- Jeśli typ wymaga kilku parametrów, nie masz innego wyboru, jak tylko użyć parametru typu związanego
- jeśli typ wymaga dolnej granicy, nie masz innego wyboru, jak tylko użyć ograniczonego symbolu wieloznacznego
- „Producenci” mają górne granice, „konsumenci” mają niższe
- Nie używaj symboli wieloznacznych w typach zwracanych