在Java中遍历任何类型的通用数组

7
如果有 Java 集合的实例可以携带原始类型、泛型数组和/或可迭代集合,我想将泛型数组视为可迭代集合,但如何做呢?例如以下伪代码:
List<?> list1; 
list1.add(new int[2]); 
list1.add(new String[3]); 
list1.add(new ArrayList());
for (Object e : list1){
    if (e instanceof Iterable){ 
        //The int[2] and String[3] will not fall in this case that I want it be
        //Iterate within e
    }
}

请指导如何使 int[2] 和 String[3] 适应此情况。
谢谢和问候, William

我可能错了(我经常这样),但我认为我提供了答案,让您可以在不知道确切类型的情况下迭代通用集合。 - Petro Semeniuk
@Petro Semeniuk:你的解决方案可行,但它将数组作为一种特殊情况并对其进行了不同处理。原问题的实质(至少是我理解的)是如何避免这样做。我们如何使数组的行为与我们的其他可迭代对象相同,而不需对它们单独处理。 - Asaph
@Asaph。谢谢。我真的误解了原来的问题。将数组包装成集合确实是最好的解决方案。干杯! - Petro Semeniuk
6个回答

11
使用反射包中的Array类:
    final List<Object> list = new ArrayList<Object>();
    list.add(new int[] { 1, 2 });
    list.add(new String[] { "a", "b", "c" });
    final List<String> arrayList = new ArrayList<String>();
    arrayList.add("el1");
    list.add(arrayList);

    for (Object element : list) {
        if (element instanceof Iterable) {
            for (Object objectInIterable : (Iterable) element) {
                System.out.println(objectInIterable);
            }
        }
        if (element.getClass().isArray()) {
            for (int i = 0; i < Array.getLength(element); i++) {
                System.out.println(Array.get(element, i));
            }
        }
    }

4

在循环中,您可以使用适当的数组操作符instanceof

对于int[]

if (e instanceof int[]) {
   // ...
}

对于对象数组(包括字符串数组):

if (e instanceof Object[]){
    // ...
}

或者,当将数组添加到主List时,您可以将每个数组包装在Arrays.asList()中。在这种情况下,您可以使用List<List>泛型而不是通配符泛型List<?>,并避免使用instanceof检查数据类型的需要。像这样:

List<List> list1; 
list1.add(Arrays.asList(new int[2])); 
list1.add(Arrays.asList(new String[3])); 
list1.add(new ArrayList());
for (List e : list1){
    // no need to check instanceof Iterable because we guarantee it's a List
    for (Object object : e) {
        // ...
    }
}

如果你在使用 instanceof 和泛型的时候,就有一种感觉,你可能没有正确地使用泛型。


能否像这样做:“e instanceof T[]”,其中T是类型参数<T>? - William X
@William Choi:不可能,因为类型擦除的缘故。instanceof 在运行时发生,而 T[] 在编译时就被丢失了。 - Asaph
明白了。我误解了 T[] 数组将在运行时保留的事实。 - William X
如果您只需要遍历这些项,请使用 List<Iterable> 而不是 List<List>。这样,您就可以灵活地存储其他可迭代的东西,例如 Set - Wyzard

3
您无法向 List<?> 添加内容。如果您需要一个包含异构元素的列表,请使用 List<Object>
但是,既然您想要遍历列表中的元素,为什么不使用 List<Iterable<Object>> 呢?如果要添加数组,请使用 Arrays.asList(myarray) 将其转换为实现了 Iterable 接口的对象。
final List<Iterable<? extends Object>> list1 = new ArrayList<Iterable<? extends Object>>();

list1.add(Arrays.asList(new int[2]));
list1.add(Arrays.asList(new String[3])); 
list1.add(new ArrayList<Integer>());

for (final Iterable<? extends Object> e : list1) {
    for (final Object i : e) {
        // ...
    }
}

如果你想在列表中存储非可迭代的事物,那么你需要使用 List<Object>instanceof 检查,但你仍然可以使用 Arrays.asList() 将数组转换为可迭代对象,避免将数组作为特殊情况处理。

是的,我们无法将元素添加到List <?>中。但是我们可以在方法参数中使用List <?>。我只是试图说明这种情况,抱歉让您感到困惑。回到问题上来,我真的很好奇是否存在一种方法可以做到类似“e instanceof T []”的事情,其中“T”是类型参数。 - William X
@William Choi,不可以这样做,因为类型参数T仅存在于编译时; 在运行时,它实际上只是Object。如果您需要在运行时知道参数化类型,则可以让调用者传递一个Class<T>类型的参数。编译器将强制执行仅传递正确的类对象,并且您可以使用类对象上的方法,例如isInstance()isArray()getComponentType() - Wyzard

1

数组没有实现Iterable接口。

public class StackOverflow
{
    public static void main(final String[] argv)
    {
        display(new int[0].getClass());
    }

    private static void display(final Class clazz)
    {
        final Class   superClass;
        final Class[] interfaces;

        superClass = clazz.getSuperclass();

        if(superClass != null)
        {
            display(superClass);
        }

        System.out.println(clazz.getCanonicalName());
        interfaces = clazz.getInterfaces();

        for(final Class iface : interfaces)
        {
            display(iface);
        }
    }
}

输出:

java.lang.Object
int[]
java.lang.Cloneable
java.io.Serializable

您可以在类上使用 isArray() 来判断它是否为数组:

public class StackOverflow
{
    public static void main(final String[] argv)
    {
        List<Object> list1;

        list1 = new ArrayList<Object>();
        list1.add(new int[2]);
        list1.add(new String[3]);
        list1.add(new ArrayList());

        for(Object e : list1)
        {
            if(e instanceof Iterable)
            {
                System.out.println("Iterable");
            }

            if(e.getClass().isArray())
            {
                System.out.println("array");
            }
        }
    }
}

0

使用泛型

public void printArray(T[] someArray) {
    for (T t : someArray)
        System.out.println(t);        
}

0
public class IterTest {
    public static void main(String[] args) {
        ArrayList list1 = new ArrayList();

        list1.add(new int[] { 0, 1, 2 });
        list1.add(new String[] { "SA_0", "SA_1", "SA_2" });
        list1.add(Arrays.asList(new String[] { "L_0", "L_1", "L_2" }));

        for (Object e : list1) {
            if (e instanceof Iterable) {
                iterate((Iterable) e);
            } else if (e.getClass().isArray()) {
                iterateArray(e);
            }
        }
    }

    private static void iterateArray(Object e) {
        Class type = e.getClass().getComponentType();
        if (!type.isPrimitive())        { iterate((Object[])  e); }
        else if (type == boolean.class) { iterate((boolean[]) e); }
        else if (type == double.class)  { iterate((double[])  e); } 
        else if (type == float.class)   { iterate((float[])   e); } 
        else if (type == short.class)   { iterate((short[])   e); } 
        else if (type == long.class)    { iterate((long[])    e); } 
        else if (type == char.class)    { iterate((char[])    e); }
        else if (type == byte.class)    { iterate((byte[])    e); } 
        else if (type == int.class)     { iterate((int[])     e); } 
    }

    static void iterate(Iterable  a) { for (Object  e : a) { print(e); } }
    static void iterate(Object[]  a) { for (Object  e : a) { print(e); } }
    static void iterate(boolean[] a) { for (boolean e : a) { print(e); } }
    static void iterate(double[]  a) { for (double  e : a) { print(e); } }
    static void iterate(float[]   a) { for (float   e : a) { print(e); } }
    static void iterate(short[]   a) { for (short   e : a) { print(e); } }
    static void iterate(long[]    a) { for (long    e : a) { print(e); } }
    static void iterate(char[]    a) { for (char    e : a) { print(e); } }
    static void iterate(byte[]    a) { for (byte    e : a) { print(e); } }
    static void iterate(int[]     a) { for (int     e : a) { print(e); } }

    static void print(Object o) { System.out.println(o); }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接