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