Предположим, у меня есть метод «mix», который принимает два списка, возможно, разных типов T и S, и возвращает один список, содержащий элементы обоих. В целях безопасности типов я хотел бы указать, что возвращаемый список имеет тип R, где R — это супертип, общий для T и S. Например:
List<Number> foo = mix(
Arrays.asList<Integer>(1, 2, 3),
Arrays.asList<Double>(1.0, 2.0, 3.0)
);
Чтобы указать это, я мог бы объявить метод как
static <R, T extends R, S extends R> List<R> mix(List<T> ts, List<S> ss)
Но что, если я хочу сделать mix
методом экземпляра вместо статического в классе List2<T>
?
<R, T extends R, S extends R> List<R> mix ...
затеняет <T>
на экземпляре List2
, так что это нехорошо.
<R, T extends S&T, S extends R> List<R> mix ...
решает проблему затенения, но не принимается компилятором
<R super T, S extends R> List<R> mix ...
отклоняется компилятором, поскольку подстановочные знаки с нижней границей нельзя хранить в именованной переменной (используется только в выражениях ? super X
)
Я мог бы переместить аргументы в сам класс, например List2<R, T extends R, S extends R>
, но информация о типе действительно не имеет значения на уровне экземпляра, потому что она используется только для одного вызова метода, и вам придется повторно приводить объект каждый раз, когда вы хотите для вызова метода с разными аргументами.
Насколько я могу судить, с помощью дженериков это сделать невозможно. Лучшее, что я могу сделать, это вернуть необработанное List2
и привести его к callsite, как до того, как были введены дженерики. У кого-нибудь есть лучшее решение?
S extends T
вместоS extends R
? - person Rohit Jain   schedule 19.08.2013mix
. Что именно ты в нем делаешь? Вам действительно нужны эти параметры типа? Похоже, вместо этого вы можете использовать ограниченные подстановочные знаки. - person Rohit Jain   schedule 19.08.2013R
. Поскольку вы просто собираетесь вернутьList<Number>
, просто укажите это как тип возвращаемого значения. Честно говоря, я не вижу здесь никакого применения универсального метода. - person Rohit Jain   schedule 19.08.2013List<Number>
— это всего лишь пример. Я хочу, чтобы он мог смешивать любые два типа. Тривиальная реализацияmix
может быть простоArrayList<R> result = new ArrayList<>(ts.size() + ss.size()); result.addAll(ts); result.addAll(ss); return result;
- person Matt G   schedule 19.08.2013<R super T, S extends R> List<R>
действительно имеет смысл. Связанный пост: Ограничение дженериков ключевым словом "super". Возможно, вам придется согласиться на сохранение статического метода. - person Paul Bellora   schedule 19.08.2013T
кR
в объявлении типаList2
. Что бы просто переместить параметры типа в объявлении метода в объявление класса:class List2<R, T extends R, S extends R>
, что, как я полагаю, не то, что вы хотели. - person Edwin Dalorzo   schedule 19.08.2013R super T
не поддерживается. - person Rohit Jain   schedule 19.08.2013