views:

271

answers:

3

How can I see in Java if an Object is an array without using reflection? And how can I iterate through all items without using reflection?

I use Google GWT so I am not allowed to use reflection :(

I would love to implement the following methods without using refelection:

private boolean isArray(final Object obj) { ??.. }

private String toString(final Object arrayObject) { ??.. }

BTW: neither do I want to use Javascript such that I can use it in non-GWT environments

Ed

+6  A: 

You can use instanceof.

JLS 15.20.2 Type Comparison Operator instanceof

 RelationalExpression:
    RelationalExpression instanceof ReferenceType

At run time, the result of the instanceof operator is true if the value of the RelationalExpression is not null and the reference could be cast to the ReferenceType without raising a ClassCastException. Otherwise the result is false.

That means you can do something like this:

Object o = new int[] { 1,2 };
System.out.println(o instanceof int[]); // prints "true"        

You'd have to check if the object is an instanceof boolean[], byte[], short[], char[], int[], long[], float[], double[], or Object[], if you want to detect all array types.

Also, an int[][] is an instanceof Object[], so depending on how you want to handle nested arrays, it can get complicated.

For the toString, java.util.Arrays has a toString(int[]) and other overloads you can use. It also has deepToString(Object[]) for nested arrays.

public String toString(Object arr) {
   if (arr instanceof int[]) {
      return Arrays.toString((int[]) arr);
   } else //...
}

It's going to be very repetitive (but even java.util.Arrays is very repetitive), but that's the way it is in Java with arrays.

See also

polygenelubricants
I think you have a typo - the toString methods have only one argument.
Eyal Schneider
@Eyal: fixed! It was leftover thoughts from my previous answer!
polygenelubricants
Nice answer, and very useful side-bar references.
Software Monkey
Thanks, it didn't realize it's that simple. Thought insstanceof couldn't be used straightforward with T[] :(
edbras
BTW: I also noticed another nice way to discover if something is an arrayClass.isArray() (used in the Arrays.deepToString()).
edbras
@edbras: yes, that's what Steve Kuo was saying down below. My solution uses pure linguistic construct instead of API call.
polygenelubricants
It works fine, I only don't use instanceof but getClass as comparision.Something like:if (array.getClass == int[].class) { Arrays.toString((int[]) array);}Thanks all..
edbras
@edbras: That's how `java.util.Arrays` does it, yes. I see that you've been reading the code I linked to.
polygenelubricants
+2  A: 

There is no subtyping relationship between arrays of primitive type, or between an array of a primitive type and array of a reference type. See JLS 4.10.3.

Therefore, the following is incorrect:

public boolean isArray(final Object obj) {
    return obj instanceof Object[];
}

I use Google GWT so I am not allowed to use reflection :(

The best solution (to the isArray array part of the question) depends on what counts as "using reflection".

If calling obj.getClass().isArray() does not count as using reflection, then that is the best solution. Otherwise, the best way of figuring out whether an object has an array type is to use a sequence of instanceof expressions.

public boolean isArray(final Object obj) {
    return obj instanceof Object[] || obj instanceof boolean[] ||
           obj instanceof byte[] || obj instanceof short[] ||
           obj instanceof char[] || obj instanceof int[] ||
           obj instanceof long[] || obj instanceof float[] ||
           obj instanceof double[];
}

You could also try messing around with the name of the object's class as follows, but the call to obj.getClass() is bordering on reflection.

public boolean isArray(final Object obj) {
    return obj.getClass() != null &&
           obj.getClass().toString().charAt(0) == '[';
}
Stephen C
Fixed that ... thanks
Stephen C
A: 

You can use Class.isArray()

public static boolean isArray(Object obj)
{
    return obj!=null && obj.getClass().isArray();
}

This works for both object and primitive type arrays.

For toString take a look at Arrays.toString. You'll have to check the array type and call the appropriate toString method.

Steve Kuo
And then how do you do `toString`? How do you call it from `Object obj`? I really don't mind you downvoting me and Stephen C., but at least your answer has to be better, and `isArray` is marginal improvement at best.
polygenelubricants
I would say that isArray is a little more than a "marginal improvement" over doing 9 instanceof checks. Less code is better. If Java were to add a new primitive isArray would still work. isArray is also a native method, so performance should be better.
Steve Kuo
@Steve: it's marginal because you'd still need `instanceof` to do the dirty work for `Arrays.toString`. Mentioning `isArray` is great as a comment on Stephen C.'s answer (which also uses `getClass()`), but it's not really useful as its own answer, and downvoting the more complete answers based on `isArray` is just ... I don't know the word for it.
polygenelubricants
@Steve: read what votes mean. Downvotes mean the answer is "not useful". Both Stephen and my answers are a lot more useful than yours (though again, pointing out `isArray` is great as a comment).
polygenelubricants
Hey @polygenelubricants ... it's OK. If we really cared, we could always downvote his answer to -2 in retaliation. :-)
Stephen C