#java #generics #iterator
#java #общие #итератор
Вопрос:
Я хотел бы выполнить итерацию по коллекции, передаваемой в универсальный метод, например:
public <T> int oddNumberCounter(T collectionOfNums) {
int count = 0;
Iterator<Integer> integerIterator = collectionOfNums.iterator();
while(integerIterator.hasNext()) {
int current = integerIterator.next();
if (oddNumberCheck(current))
count ;
}
return count;
}
Однако, похоже, что collectionOfNums не воспринимается как коллекция, как я думаю, это должно быть сделано. Действительно ли это нужно сделать, если нет, то как лучше всего это сделать?
Комментарии:
1. тип collectionOfNums должен быть Collection<T> , а не T. Но в любом случае, зачем вам нужен универсальный метод, когда вы явно работаете с целыми числами? Отмените дженерики!
2. Прохождение этого руководства по вопросам — docs.oracle.com/javase/tutorial/java/generics/QandE /…
Ответ №1:
collectionOfNums не воспринимается как коллекция, как я думаю, это должно быть сделано.
Вы постановили, что у этого метода есть переменная типа (это то <T>
, о чем идет речь), и что об этой переменной типа абсолютно ничего не известно (иначе вы бы написали <T extends Number>
, например). Почему java делает вывод, что T поэтому должен быть коллекцией? Generics не имеет (почти) ничего общего с выводом. Возможно, вы считаете, что дженерики по своей сути связаны с коллекциями. Или, возможно, вы думаете так: эй, я обращаюсь iterator()
к нему позже, и это метод, который есть только в коллекциях (кстати, это false). Это не так, как это работает; дженерики предназначены для любого места, где вам нужно параметризовать типы. Коллекции — это лишь одна из многих вещей, которым это нравится.
В основе вы могли бы сделать это:
public <T> int oddNumberCounter(Collection<T> collectionOfNums) {
...
}
но это все равно не то, что вы хотите: дженерики служат для объединения типов вместе. Если вы используете переменную типа ровно в одном месте, это совершенно бесполезно. Итак, вышесказанное бесполезно. Вместо этого вы бы написали:
public int oddNumberCounter(Collection<?> collectionOfNums) {
...
}
за исключением того, что это все еще не то, что вы хотите: это прямо там, в названии, вам нужен набор чисел. Итак, добавьте привязку типа:
public <T extends Number> int oddNumberCounter(Collection<T> collectionOfNums) {
....
}
за исключением того, что мы можем упростить это и избавиться от T, возвращаясь к использованию вопросительного знака (по-прежнему бывает, что буквы служат для типов ссылок, и мы все еще используем его только один раз, поэтому бесполезно). Собрать все это вместе:
public int oddNumberCounter(Collection<? extends Number> collectionOfNums) {
int count = 0;
for (Number n : collectionOfNums) {
if (n.intValue() % 2 != 0) count ;
}
return count;
}
Обратите внимание, что это рассматривает, например 5.2
, (double) как «нечетное», потому что его intvalue равно «5», и это нечетно. Я почти уверен, что вы действительно хотите Collection<Integer>
вместо этого, и никаких общих ограничений вообще.
Это отличается от Collection<Number>
того, что вы можете вызвать этот метод и передать, например, an ArrayList<Integer>
, или a LinkedList<Double>
и так далее.
Ответ №2:
Можно определить универсальный параметр, как <? extends Collection> поэтому компилятор Java знает, она должна принимать сбор.