If there is an instance of Java Collection which may carry primitive type, generic array, and/or iterable collection, I want to treat the generic array as Iterable collection, but how? e.g. the following pseudo java code
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
}
}
Please advise how to make the int[2] and String[3] fall in t开发者_Go百科he case.
Thanks & regards, William
Use Array class from reflection package:
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));
}
}
}
Within your loop, you could use the appropriate array operand for instanceof
.
For int[]
:
if (e instanceof int[]) {
// ...
}
For Object
arrays (including String[]
):
if (e instanceof Object[]){
// ...
}
Alternatively, when adding your arrays to your master List
, you could wrap each one in Arrays.asList()
. In that case, you could use the List<List>
generic instead of the wildcard generic List<?>
and avoid the need to check the data type with instanceof
. Something like this:
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) {
// ...
}
}
Anytime you're using instanceof
and generics together, it's a smell that you may be doing something not quite right with your generics.
You can't add things to a List<?>
. If you want a list of heterogeneous things, use a List<Object>
.
However, since you want to iterate over the things in your list, why not use a List<Iterable<Object>>
? To add an array, use Arrays.asList(myarray)
to get something that implements Iterable
from it.
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) {
// ...
}
}
If you want to store non-iterable things in your list too, then you'll need to use List<Object>
and the instanceof
check, but you can still use Arrays.asList()
to turn arrays into iterables, avoiding the need to handle arrays as a special case.
Arrays do not implement the Iterable interface.
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);
}
}
}
Output:
java.lang.Object
int[]
java.lang.Cloneable
java.io.Serializable
You can use isArray()
on the class to see if it is an array:
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");
}
}
}
}
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); }
}
Use generics
public void printArray(T[] someArray) {
for (T t : someArray)
System.out.println(t);
}
精彩评论