假设我有一个方法接受一个数组并使用内置for-each loop内置的Java处理其中的每个元素,如下所示:
public static void myFun(SomeClass[] arr) {
for (SomeClass sc : arr) {
// Stuff is processed here
}
}
这很好用,但现在我希望能够传递相同的方法List<SomeClass>
。我是否注定要使用Collection.toArray(T []),还是我可以使用myFun()
接受任何可以在for-each构造中使用的类型的参数?
澄清一下:我想要一个接受任何可迭代对象的方法签名,无论是原始数组还是Collection。我可以很容易地编写两种方法,一种方法包装另一种方法,但我只是好奇是否有更好的方法。
答案 0 :(得分:9)
我建议使用Iterable
,Collection
或List
作为参数类型。
IMO,集合应该优先于引用数组。如果您碰巧有一个数组Arrays.asList
,那么转换很顺利。 Arrays.asList
允许获取并返回到数组,但显然不是“结构”修改会改变数组长度。
myFun(Arrays.asList(arr));
您可能必须在极端/一般情况下使用通配符。
public static void myFun(Iterable<? extends SomeClass> somethings) {
for (SomeClass something : somethings) {
// something is processed here
}
}
值得注意的是Collections.toArray
和Arrays.asList
的工作方式略有不同。 asList
使原始数组保留回集合,因此对集合的更改将反映在数组中。 Collections.toArray
生成集合数据的(浅)副本。如果要返回数组,那么复制通常是您想要的。不对称,如果您作为参数传递,通常不会复制(除非存储为字段)。
答案 1 :(得分:5)
使用 Iterable
。这就是它的用途。
正如你所说,Iterable
将无法处理数组。
您不希望使用多个方法相互包装。这排除了Arrays.asList
和Collection.toArray
。
所以你的问题的答案是否定的,没有办法。但是,如果您可以使用Lists
,为什么要使用数组?
我仍然会在这里Iterable
。我比Collection
更喜欢它,因为在过去我有过实现Iterable
但不是集合的类;这使得他们可以根据需要轻松地检索值,并且可以在它们上使用foreach循环。
答案 2 :(得分:3)
你不能,java Arrays不实现Iterable:
public static int sum(Iterable<Integer> elements) {
int s = 0;
for (int i : elements) {
s += i;
}
return s;
}
public static void main(String[] args) {
L1: System.out.println(sum(1,2,3));
L2: System.out.println(sum(Arrays.asList(1,2,3)));
L3: System.out.println(sum(new int[] { 1,2,3 }));
}
这导致(L1和L3)中的两个编译时错误;所以你必须设计你的 接受Iterable(Collections)和/或Array的方法,至少有一个方法必须执行一些转换(到/从数组)
解决方法强>:
您可以尝试使用适配器:
public class ArrayIterator<T> implements Iterator<T> {
private final T[] array;
private int i;
public ArrayIterator(T[] anArray) {
array = anArray;
i = 0;
}
public boolean hasNext() {
return i < array.length;
}
public T next() {
return array[i++];
}
public void remove() {
throw new UnsupportedOperationException();
}
}
private static int sum(final Integer ... elements) {
return sum(new Iterable<Integer>() {
public Iterator<Integer> iterator() {
return new ArrayIterator<Integer>(elements);
}
});
}
只有在处理原始数组时才应注意;当你只使用 引用对象(您的情况)ArrayIterator +匿名类很酷
希望有所帮助
答案 3 :(得分:1)
简短回答:不,没有单一的方法签名类型 - 安全地接受Iterable和数组。显然你可以接受Object
,但这也是一个黑客攻击。
Long-ish回答:由于增强的for
- 循环被有效地定义了两次(一次用于数组,一次用于Iterable
),你还需要提供两个重载方法:
public static void myFun(SomeClass[] array) {
for (SomeClass sc : array) {
doTheProcessing(sc);
}
}
public static void myFun(Iterable<? extends SomeClass> iterable) {
for (SomeClass sc : iterable) {
doTheProcessing(sc);
}
}
尽管两种方法的来源看起来完全相同,但您需要定义两次(除非您将数组包装在您自己的Iterable
中,如@dfa所述)。
答案 4 :(得分:0)
Java 1.5+中有一些Java Generics的特性,您可以在方法调用和构造函数中使用<? extends Subtype>
。您可以使用<? extends Object>
,然后处理这些内容的任何内容都只能访问Object上的方法。你可能真正想要的是更像这样的东西:
List<? extends MyCrustaceans> seaLife = new ArrayList<? extends MyCrustaceans>();
MyShrimp s = new MyShrimp("bubba");
seaLife.add(s);
DoStuff(seaLife);
...
public static void DoStuff(List<? extends MyCrustaceans> seaLife)
{
for (MyCrustaceans c : seaLife) {
System.out.println(c);
}
}
因此,如果您有一个基类(如MyCrustaceans),您可以在DoStuff中使用该基类的任何方法(如果参数为<? extends Object>
,则可以使用Object类中的任何方法)。 <? super MyType>
有一个类似的特性,它接受一个给定类型的超类型的参数,而不是子类型。对于你可以用这种方式使用“扩展”和“超级”的东西有一些限制。这是一个good place to find more info。
答案 5 :(得分:-3)
public static void myFun(Collection<MyClass> collection) {
for (MyClass mc : collection) {
// Stuff is processed here
}
}