Это зависит от того, что вам нужно делать. Вам нужно использовать параметр ограниченного типа, если вы хотите сделать что-то вроде этого:
public <T extends Shape> void addIfPretty(List<T> shapes, T shape) {
if (shape.isPretty()) {
shapes.add(shape);
}
}
Здесь у нас есть a List<T> shapes
и a T shape
, поэтому мы можем смело shapes.add(shape)
. Если он был объявлен List<? extends Shape>
, вы НЕ можете безопасно add
перейти к нему (потому что у вас могут быть a List<Square>
и a Circle
).
Таким образом, давая имя параметру ограниченного типа, у нас есть возможность использовать его в другом месте нашего универсального метода. Конечно, эта информация не всегда требуется, поэтому, если вам не нужно так много знать о типе (например, вашdrawAll
), тогда достаточно подстановочного знака.
Даже если вы снова не ссылаетесь на параметр ограниченного типа, параметр ограниченного типа по-прежнему требуется, если у вас есть несколько границ. Вот цитата из FAQs Анжелики Лангер по Java Generics
В чем разница между привязкой подстановочного знака и привязкой параметра типа?
Подстановочный знак может иметь только одну границу, а параметр типа может иметь несколько границ. Подстановочный знак может иметь нижнюю или верхнюю границу, в то время как нижняя граница для параметра типа отсутствует.
Границы подстановочных знаков и границы параметров типа часто путают, потому что они оба называются границами и имеют частично похожий синтаксис. […]
Синтаксис :
type parameter bound T extends Class & Interface1 & … & InterfaceN
wildcard bound
upper bound ? extends SuperType
lower bound ? super SubType
Подстановочный знак может иметь только одну границу: нижнюю или верхнюю. Список границ подстановочных знаков не разрешен.
Параметр типа в качестве ограничения может иметь несколько границ, но не существует такой вещи, как нижняя граница для параметра типа.
Цитаты из Effective Java 2nd Edition, пункт 28: Используйте ограниченные символы подстановки для повышения гибкости API :
Для максимальной гибкости используйте типы подстановочных знаков для входных параметров, которые представляют производителей или потребителей. […] PECS означает производитель- extends
, потребитель- super
[…]
Не используйте подстановочные знаки в качестве возвращаемых типов . Вместо того, чтобы обеспечивать дополнительную гибкость для ваших пользователей, это заставит их использовать типы подстановочных знаков в клиентском коде. При правильном использовании типы подстановочных знаков почти не видны пользователям класса. Они заставляют методы принимать параметры, которые они должны принимать, и отклонять те, которые они должны отклонять. Если пользователю класса приходится думать о типах подстановочных знаков, вероятно, что-то не так с API класса .
Применяя принцип PECS, мы можем теперь вернуться к нашему addIfPretty
примеру и сделать его более гибким, написав следующее:
public <T extends Shape> void addIfPretty(List<? super T> list, T shape) { … }
Теперь мы можем addIfPretty
, скажем, от a Circle
до a List<Object>
. Это очевидно типизировано, но все же наше исходное объявление не было достаточно гибким, чтобы позволить это.
Связанные вопросы
Резюме
- Используйте параметры / подстановочные знаки ограниченного типа, они повышают гибкость вашего API.
- Если для типа требуется несколько параметров, у вас нет другого выбора, кроме как использовать параметр ограниченного типа.
- если для типа требуется нижняя граница, у вас нет выбора, кроме как использовать ограниченный подстановочный знак
- "Производители" имеют верхнюю границу, "потребители" - нижнюю.
- Не используйте подстановочные знаки в возвращаемых типах