Использование итератора для параметра универсального метода

#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 знает, она должна принимать сбор.