【问题标题】:Iterating generic array of any type in Java在Java中迭代任何类型的泛型数组
【发布时间】:2010-12-03 04:30:28
【问题描述】:

如果有一个 Java 集合的实例可以携带原始类型、泛型数组和/或可迭代集合,我想将泛型数组视为可迭代集合,但是如何处理呢?例如以下伪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] 落入本案。

感谢和问候, 威廉

【问题讨论】:

  • 我可能是错的(我经常是),但我想我提供了答案,您可以在不知道确切类型的情况下迭代泛型集合。
  • @Petro Semeniuk:您的解决方案有效,但它使数组成为一种特殊情况并以不同方式对待它们。原始问题的精神(至少在我的解释中)是我们如何避免这样做。我们如何才能使数组的行为与我们的其他 Iterable 一样,而不单独对待它们。
  • @Asaph。谢谢。我真的误解了原来的问题。将数组包装到集合中确实是最好的解决方案。干杯!

标签: java generics loops


【解决方案1】:

使用反射包中的 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));
            }
        }
    }

【讨论】:

    【解决方案2】:

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

    对于int[]

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

    对于Object 数组(包括String[]):

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

    或者,当您将数组添加到您的主List 时,您可以将每个数组包装在Arrays.asList() 中。在这种情况下,您可以使用List&lt;List&gt; 泛型而不是通配符泛型List&lt;?&gt;,并避免使用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 是类型参数
    • @William Choi:不。这是不可能的,因为类型擦除。 instanceof 发生在运行时,T[] 在编译后丢失。
    • 知道了。我误解了 T[] 将在运行时保留。
    • 如果您需要对这些项目进行迭代,请使用List&lt;Iterable&gt;,而不是List&lt;List&gt;。这样您就可以灵活地存储其他可迭代的内容,例如 Set
    【解决方案3】:

    您不能向List&lt;?&gt; 添加内容。如果您想要一个异构事物的列表,请使用List&lt;Object&gt;

    但是,既然您想遍历列表中的内容,为什么不使用List&lt;Iterable&lt;Object&gt;&gt;?要添加数组,请使用 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&lt;Object&gt;instanceof 检查,但你仍然可以使用 Arrays.asList() 将数组转换为可迭代对象,避免需要将数组作为特殊情况处理。

    【讨论】:

    • 是的,我们不能将元素添加到列表中>。但是我们可以在方法参数中使用 List>。我只是想说明这种情况,很抱歉造成混淆。回到这个问题,我真的很好奇是否有一种方法可以做类似“e instanceof T[]”之类的事情,其中​​“T”是类型参数。
    • @William Choi,不,你不能那样做,因为类型参数 T 只存在于编译时;在运行时它实际上只是对象。如果需要在运行时知道参数化类型,可以让调用者传入Class&lt;T&gt;类型的参数。编译器将强制只传递正确的类对象,您可以在类对象上使用isInstance()isArray()getComponentType() 等方法。
    【解决方案4】:

    数组不实现 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");
                }
            }
        }
    }
    

    【讨论】:

      【解决方案5】:
      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); }
      }
      

      【讨论】:

        【解决方案6】:

        使用泛型

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-01
          • 2015-07-03
          相关资源
          最近更新 更多