英文:
Using iterator on paramater of generic method
问题
我想对传递给泛型方法的集合进行迭代,代码如下:
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
并没有被视为我认为应该的集合。这样做是有效的吗?如果无效,有什么最佳实践的方法可以解决这个问题?
英文:
I'd like to iterate over a collection being passed in to a generic method like so:
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;
}
However, it seems like collectionOfNums is not being picked up as a collection as I think it should do. Is this a valid thing to do, if not, what would be the best way to go about it?
答案1
得分: 2
> collectionOfNums is not being picked up as a collection as I think it should do.
你认为这个方法具有类型变量(这就是 <T>
的含义),并且对这个类型变量一无所知(否则你会写成 <T extends Number>
)。为什么 Java 会推断 T 必须是一个集合呢?泛型与推断几乎没有关系。也许你认为泛型与集合有固有的关联。或者你的想法是:嘿,我稍后在它上面调用 iterator()
,而这是只有集合才有的方法(顺便说一下,这是错误的)。事实并非如此;泛型可以用于任何需要参数化类型的地方。集合只是许多需要这样的东西之一。
基本上你可以这样做:
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',而 5 是奇数。我很确定你实际上想要 Collection<Integer>
,而且不需要任何泛型边界。
这与 Collection<Number>
不同,因为你可以调用这个方法并传入例如 ArrayList<Integer>
、LinkedList<Double>
等等。
英文:
> collectionOfNums is not being picked up as a collection as I think it should do.
You've decreed that this method has a type variable (that is what the <T>
is about), and that this type variable has absolutely nothing known about it (otherwise you'd have written <T extends Number>
for example). Why would java infer that T must therefore be a collection? Generics has (almost) nothing to do with inference. Perhaps you think generics are inherently related to collections. Or perhaps your thinking is: Hey, I call iterator()
on it later, and that is a method only collections have (that's false, by the way). This isn't how it works; generics are for anywhere you need to parameterize types. Collections is just one of many things that like that.
In basis you could do this:
public <T> int oddNumberCounter(Collection<T> collectionOfNums) {
...
}
but this still isn't what you want: Generics serve to link types together. If you use a type variable in exactly one spot it is completely useless. So, the above is useless. Instead, you'd write:
public int oddNumberCounter(Collection<?> collectionOfNums) {
...
}
except that still isn't what you want: It's right there in the name, you want a collection of numbers. So, add a type bound:
public <T extends Number> int oddNumberCounter(Collection<T> collectionOfNums) {
....
}
except we can simplify that and get rid of the T, going back to the question mark usage (it's still the case that the letters serve to link types, and we're still only using it once, therefore, useless). Putting it all together:
public int oddNumberCounter(Collection<? extends Number> collectionOfNums) {
int count = 0;
for (Number n : collectionOfNums) {
if (n.intValue() % 2 != 0) count++;
}
return count;
}
Note that this considers e.g. 5.2
(the double) as 'odd', because its intvalue is '5', and that is odd. I'm pretty sure you really want Collection<Integer>
instead, and no generic bounds whatsoever.
This is different from Collection<Number>
, in that you can invoke this method and pass in e.g. an ArrayList<Integer>
, or a LinkedList<Double>
, etcetera.
答案2
得分: -1
你可以将泛型参数定义为<? extends Collection<Integer>>,这样Java编译器就知道它必须接受一个集合。
英文:
You can define the generic parameter as <? extends Collection<Integer>> so the Java compiler knows it must accept a collection.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论