java - Java: 数组和集合有公共接口或者超类?

  显示原文与译文双语对照的内容

是否有可能检查一个对象是 array 还是带有一个子句的Collection? 我正在尝试实现的内容:

假设,array 将实现 arraylist,假设对象foo可以是 array 或者 Collection,我想使用如下代码片段:


if (foo instanceof Iterable) {


 for (Object f : (Iterable) foo) {


//do something with f


 }


}



不幸的是,array 不能转换为 Iterable 。 它也不实现 Collection 。 是否有其他可能在一个循环中进行处理? 当然,--使用an子句和两个循环( 那是不可能的) 来代替 -- 。

编辑:响应这些答案。 我知道 isArray() 方法,但是在这种情况下,


...


for (Object f : (Iterable) foo) {


...



由于一个foreach循环和集合和数组同时工作,因这里不能使用这两个循环。

时间:

Class#isAssignableFrom 可能会派上用场。


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();



它也适用于原始的array 类。

我做了一个小测试"


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



可以通过从 Class 中使用 isArray() 方法检查对象是否为 array


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



}



你可以为此编写一个 helper 方法:


@SuppressWarnings("unchecked")


public static <E> void forEach(Object arrayOrIterable, Consumer<? super E> action) {


 Objects.requireNonNull(arrayOrIterable);


 if (arrayOrIterable instanceof Iterable) {


 for (Object o : (Iterable<?>) arrayOrIterable) {


 action.accept((E) o);


 }


 } else if (arrayOrIterable.getClass().isArray()) {


 int length = Array.getLength(arrayOrIterable);


 for (int i = 0; i <length; i++) {


 action.accept((E) Array.get(arrayOrIterable, i));


 }


 } else {


 throw new IllegalArgumentException("not an array nor iterable:" + arrayOrIterable.getClass());


 }


}



第二个分支利用 java.reflect.Array 类提供 helper 方法( 可能很慢),以获取 array 和给定索引处的元素的length

你可以这样调用它:


int[] ints = {1, 2, 3, 4};


forEach(ints, (Integer i) -> System.out.println(i));



List<Integer> ints = Arrays.asList(1, 2, 3, 4);


forEach(ints, (Integer i) -> System.out.println(i));



由于泛型的性质,这里方法可以能引发 ClassCastException,比如 这里调用:


int[] ints = {1, 2, 3, 4};


forEach(ints, (String s) -> System.out.println(s));



将导致:


java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String



根据你尝试执行的操作,你可能希望实现两种类似的方法:


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));



}



我不确定这是否有助于你,因为你似乎已经在某个变量中有问题了。 但是如果你能解决这个问题,那就很有用了。

...