19

So I have an Object which MIGHT be an array. It can also be primitive, or a string. If it is an array, it can be an array of literally anything.

I have no problem figuring out if it is an array but I can't seem to cast it into anything that I can iterate through to get the values out of.

// o is an object and clazz is the class of the o
if (clazz == Array.class) {
            Class ofArray = o.getClass().getComponentType();
            String arrayType = ofArray.getName(); // 'Double' for my test case
            //ERROR: [D cannot be cast to [Ljava.lang.Object 
            Object[] objects = (Object[]) o; 
    }

My background is in ruby and php (where it would just work) and the static typing is messing with my head. Any ideas?

EDIT:

This throws the error

[D cannot be cast to [Ljava.lang.Object.

What am I missing?

if (o.getClass().isArray()) {
    Object[] objects = (Object[]) o;  
}
Gray
  • 115,027
  • 24
  • 293
  • 354
Ryan Epp
  • 931
  • 1
  • 10
  • 21
  • You can test an object to see if it's an array. This question addresses that: http://stackoverflow.com/questions/219881/java-array-reflection-isarray-vs-instanceof Then you can cast is safely and iterate over it. – Marvo May 07 '13 at 19:52
  • so why doesn't the cast in my example work? – Ryan Epp May 07 '13 at 19:55
  • Not sure, but perhaps that particular object wasn't an array. `clazz == Array.class` perhaps let some non-array objects through. – Marvo May 07 '13 at 20:04
  • hmm... stil not working even with the alternate check for an array. See the updated question. – Ryan Epp May 07 '13 at 20:09
  • Try running it in the debugger, pause on that line, and see what type `o` actually is. – Marvo May 07 '13 at 20:18
  • *Why* do you not know anything about it? What do you plan to do with the objects in the array? You probably want to investigate Java's [generics](http://docs.oracle.com/javase/tutorial/java/generics/) instead. – Thorn G May 07 '13 at 20:39
  • I'm parsing XML into useable java 'things.' I don't know anything about the array because I don't know anything about the XML being parsed. – Ryan Epp May 07 '13 at 20:42
  • This answer might be good for you: http://stackoverflow.com/a/5608477/1354879 – Balazs Zsoldos May 07 '13 at 20:53

4 Answers4

25

If you do not want to make the switch for all primitive types you could do like this:

if (ofArray.isPrimitive()) {
    int length = Array.getLength(o);
    for (int i = 0; i < length; i++) {
        Object obj = Array.get(o, i);
        System.out.println(obj);
    }
}
else {
    Object[] objects = (Object[]) o;
    for (Object obj : objects) {
        System.out.println(obj);
    }
}

Edit: If you don't want to loop in two different places in your code use this method to convert the primitive arrays to an object array:

static Object[] convertToObjectArray(Object array) {
    Class ofArray = array.getClass().getComponentType();
    if (ofArray.isPrimitive()) {
        List ar = new ArrayList();
        int length = Array.getLength(array);
        for (int i = 0; i < length; i++) {
            ar.add(Array.get(array, i));
        }
        return ar.toArray();
    }
    else {
        return (Object[]) array;
    }
}
Vegard
  • 4,352
  • 1
  • 27
  • 25
  • 2
    This works, but beware: an implicit boxing operation is happening here: `Array.get(o, i)` - in other words, the elements of type `int` are being converted to `Integer`, the elements of type `double` are being converted to `double`, and so on. This can be inefficient in the long run – Óscar López May 07 '13 at 20:39
  • Any idea when `java.lang.reflect.Array` was added to the JDK? Is it available in 1.5 for example? – Gray Sep 14 '15 at 00:48
2

This will work for arrays with elements that are sublcasses of Object:

if (clazz.isArray()) {
    Object[] objects = (Object[]) o;
    for (Object obj : objects)
        System.out.println(obj);
}   

If you need to cast the array to an specific array type you could (ab)use instanceof but for, say, just printing the contents as strings, an Object[] suffices.

UPDATE

If the array is of primitive types, you have no option but to test for each one and cast to the correct type, Object[] won't work for this case - but there aren't that many primitive types in Java, so it won't be a gigantic switch :) . This is what I mean:

if (clazz.isArray()) {
    if (clazz.getComponentType().equals(double.class)) {
        double[] numbers = (double[]) o;
        for (double d : numbers)
            System.out.println(d);
    }
}  
Óscar López
  • 232,561
  • 37
  • 312
  • 386
  • Thanks for the response but it's still not working, check out the updated question. – Ryan Epp May 07 '13 at 20:10
  • 1
    In what line exactly is the error happening? the above code works flawlessly, the problem must be elsewhere – Óscar López May 07 '13 at 20:12
  • the error is happening on the cast. (2nd line) I've noticed that if I change my test array component type from 'double' to the corresponding wrapper 'Double' I don't get an error. – Ryan Epp May 07 '13 at 20:16
  • That's correct, this solution will not work for an array of primitives. – GriffeyDog May 07 '13 at 20:23
  • So how do I cast an Object that is actually an array of primitives to an array that I can iterate over? – Ryan Epp May 07 '13 at 20:25
  • is there really no better way than checking for each possible primitive? ... I see a large switch statement in my future =( I feel like there has to be a better way – Ryan Epp May 07 '13 at 20:31
  • @RyanEpp nope, there really isn't a better way. But cheer up, in Java there are only 8 primitive types ;) – Óscar López May 07 '13 at 20:32
  • @Ryan There are only 8 primitive types, so it's not _that_ bad. – GriffeyDog May 07 '13 at 20:32
  • Please rewrite this answer to better incorporate the "UPDATE" into the answer since the first section is misleading. – Gray Sep 14 '15 at 00:49
1

It's not enough to know your Object is an array - you should also know the underlying type of the array elements. If your array elements are of primitive type, say double, you need to

double[] doubleArray = (double[]) o;  

This won't work:

Object[] objects = (Object[]) o;  
fjf2002
  • 872
  • 5
  • 15
  • yes, but can I do this without knowing the type of primitive? (without writing a gigantic switch) – Ryan Epp May 07 '13 at 20:28
  • 1
    The way you are trying to use Java is very common in scripting languages like you mentioned: php, ruby. In statically typed languages like Java, this what you want can perhaps somehow even be achieved, but will be slow and is not considered as good coding. – fjf2002 May 07 '13 at 20:33
  • You should try to outline your problem more generally so that we can give you general tips on how to deal with that in Java. Using Object type to pass arrays, Strings and other types to methods is NOT a good idea. – fjf2002 May 07 '13 at 20:41
1

You cannot type cast an Array of primitives to an Object[]

if (clazz == Array.class) {
  Class ofArray = o.getClass().getComponentType();
  // String arrayType = ofArray.getName(); // 'Double' for my test case
  if (ofArray instanceof double.class)
    double[] doubles = (double[]) o;
  for (double d: doubles)
    System.out.println(d);
}

To create an Object[] without instanceof checks

if (!(o instanceof Object[])) {
  int len = Array.getLength(o);
  Object[] objects = new Object[len];
  for (int i = 0; i < len; i++)
    objects[i] = Array.get (o, i);
  for (Object obj: objects)
    System.out.println(obj);
}
Ravi K Thapliyal
  • 51,095
  • 9
  • 76
  • 89
  • The second version was exactly what I wanted! I don't need efficiency for debug output, just conciseness! – xeruf Oct 29 '17 at 11:41