为了账号安全,请及时绑定邮箱和手机立即绑定

是否可以编写一个循环访问集合和数组的 for 循环?

是否可以编写一个循环访问集合和数组的 for 循环?

慕的地6264312 2022-09-28 16:11:59
是否可以检查对象是数组还是具有一个子句的集合?我试图实现的目标:假设数组实现了 Iterable,并且假设 Object 可以是数组或集合,我想使用这样的代码片段:fooif (foo instanceof Iterable) {  for (Object f : (Iterable) foo) {    // do something with f  }}遗憾的是,数组不能转换为可迭代。它也不实现收集。是否有其他可能性可以像上面这样在一个循环中处理两者?而不是 - 当然 - 使用一个 if-else if 子句和两个循环(这不好)。编辑:回应这些答案。我知道 isArray() 方法,但在这种情况下,转换在...for (Object f : (Iterable) foo) {...将失败。这很可惜,也是代码冗余,因为我必须使用两个循环,尽管foreach循环同时适用于集合和数组。
查看完整描述

5 回答

?
一只名叫tom的猫

TA贡献1906条经验 获得超3个赞

关于检查 foo 是集合还是数组的条件:

类#是可分配的可能派上用场。

Class<?> fooClass = foo.getClass();

boolean isArrayOrCollection = Collection.class.isAssignableFrom(fooClass) ||

                              Object[].class.isAssignableFrom(fooClass);

我合理地假设你不会在基元数组上测试它,因为你有只使用包装类的集合。


我想你可以安全地替换为Object[].class.isAssignableFrom(fooClass)fooClass.isArray()


boolean isArrayOrCollection = Collection.class.isAssignableFrom(fooClass) ||

                              fooClass.isArray();

它也适用于基元数组类。


我运行了一个小的“测试”


class Test {

    public static void main(String[] args) {

        Predicate<Class<?>> p = c -> Collection.class.isAssignableFrom(c) || 

                                     c.isArray();


        System.out.println(p.test(new int[0].getClass()));

        System.out.println(p.test(new Integer[0].getClass()));

        System.out.println(p.test(Collections.emptyList().getClass()));

        System.out.println(p.test(Collections.emptySet().getClass()));


        System.out.println(p.test(Collections.emptyMap().getClass()));

    }

}

这导致


true

true

true

true

false

关于将同时在数组和集合上运行的泛型循环:


你根本无法写一个准确的构造来处理这个问题:(或)并且几乎没有共同点(因为一个共同的父级及其方法是不够的)。CollectionIterableObject[]Object


我认为构建自己的抽象是明智的,它将以相同的方式处理集合和数组。由于没有特定的上下文,我可以想出两个子类的简单想法,每个子类都定义了它的源代码(集合或数组)应该如何迭代。然后,对接口进行编程将有助于平等地管理它们。


一个非常简化的例子是:


interface Abstraction<T> {

    void iterate(Consumer<? super T> action);


    static <T> Abstraction<T> of(Collection<T> collection) {

        return new CollectionAbstraction<>(collection);

    }

    static <T> Abstraction<T> of(T[] array) {

        return new ArrayAbstraction<>(array);

    }

    static IntArrayAbstraction of(int[] array) {

        return new IntArrayAbstraction(array);

    }

}


class CollectionAbstraction<T> implements Abstraction<T> {

    Collection<T> source;


    public CollectionAbstraction(Collection<T> source) {

        this.source = source;

    }


    @Override

    public void iterate(Consumer<? super T> action) {

        source.forEach(action);

    }

}


class ArrayAbstraction<T> implements Abstraction<T> {

    T[] source;


    public ArrayAbstraction(T[] source) {

        this.source = source;

    }


    @Override

    public void iterate(Consumer<? super T> action) {

        for (T t : source) {

            action.accept(t);

        }

    }

}


class IntArrayAbstraction implements Abstraction<Integer> {

    int[] source;


    public IntArrayAbstraction(int[] source) {

        this.source = source;

    }


    @Override

    public void iterate(Consumer<? super Integer> action) {

        for (int t : source) {

            action.accept(t);

        }

    }

}


class Test {

    public static void main(String[] args) {

        Abstraction.of(new Integer[] {1, 2, 3}).iterate(System.out::println);

        Abstraction.of(Arrays.asList(1, 2, 3)).iterate(System.out::println);

        Abstraction.of(new int[] {1, 2, 3}).iterate(System.out::println);

    }

}

我相信上面的方法非常通用。您不依赖于某个源的迭代方式,您可以有选择地修改它们。


查看完整回答
反对 回复 2022-09-28
?
慕码人8056858

TA贡献1803条经验 获得超6个赞

其他答案都在努力回答原始标题问题:

数组和集合是否有通用接口或超类?

但你真正的问题是在身体里:

是否有其他可能性可以像上面这样在一个循环中处理两者?

答案是:不,没有办法编写一个循环访问集合和数组的 for 循环。

你可以跳过一堆箍,把数组变成列表,但你几乎肯定会得到一个比你只写两个(或更多)循环更大的混乱。打电话会告诉你你有什么,但如果没有某种演员,你仍然无法使用它。 不适用于基元数组。getClass().isArray()Arrays.asList()


查看完整回答
反对 回复 2022-09-28
?
湖上湖

TA贡献2003条经验 获得超2个赞

根据您要执行的操作,您可能需要实现两种类似的方法:


public <T> void iterateOver(List<T> list) {

    // do whatever you want to do with your list

}


public <T> void iterateOver(T[] array) {

    this.iterateOver(Arrays.asList(array));

}

或者甚至可能有一个接口:


interface ExtendedIterableConsumer<T> {


    public void iterateOver(List<T> list);


    public default void iterateOver(T[] array) {

        this.iterateOver(Arrays.asList(array));


}

我不确定这是否对你有帮助,因为你似乎已经在某个变量中拥有了有问题的对象。但是,如果你能把这个问题提高一个层次,它可能会很有用。


查看完整回答
反对 回复 2022-09-28
?
胡子哥哥

TA贡献1825条经验 获得超6个赞

您可以使用来自isArray()Class


if (foo != null && (foo.getClass().isArray() || foo instanceof Collection<?>)){


}

编辑:


在迭代此对象方面,没有简单的解决方案。但是,您可以尝试如下操作:foo


private void iterate(@NotNull Object foo) {

    if (foo instanceof Collection<?>) {

        for (Object o : ((Collection<?>) foo)) {

            chandleYourObject(o);

        }

    }


    if (foo.getClass().isArray()) {

        if (foo.getClass().isPrimitive()) {

            checkPrimitiveTypes(foo);

        }

        if (foo instanceof Object[]) {

            for (Object o : (Object[]) foo) {

                chandleYourObject(o);

            }

        }

    }

}


private void checkPrimitiveTypes(Object foo) {

    if (foo instanceof int[]) {

        for (int i : (int[]) foo) {


        }

    }

    //And the rest of primitive types

}


private void chandleYourObject(Object o ){

    //What you want to do with your object

}


查看完整回答
反对 回复 2022-09-28
?
慕丝7291255

TA贡献1859条经验 获得超6个赞

数组是对象:

https://docs.oracle.com/javase/specs/jls/se8/html/jls-10.html

抽象集合还扩展了对象:

https://docs.oracle.com/javase/8/docs/api/java/util/AbstractCollection.html

所以,是的,有一个普通的超类,但不幸的是,这并不能真正帮助你。

我建议你最好的选择是使用:

List<> someList = Arrays.asList(sourceArray)

这会将您的数组转换为实现 Iterable 的集合。您当然需要提前确定初始对象是数组还是集合,并且只有在数组时才调用上述内容,以下是一些执行此操作的选项:

boolean isArray = myArray.getClass().isArray();
boolean isCollection = Collection.class.isAssignableFrom(myList.getClass());


查看完整回答
反对 回复 2022-09-28
  • 5 回答
  • 0 关注
  • 134 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号