44

Why I cannot do this in java?

Object[] o = (Object[])(new int[]{0,1,2,3.14,4});

I have a method that receives an object and then represents it as a string, but depending on his type (primitive, primitive wrapper, array, etc...). When I was creating a Unit test, I was passing an array as Object which is Ok, but when I perform cast of that object into Object[] I'm getting ClassCastException. This is only happening with primitive type arrays. Is there any way to avoid this behavior? If not, could someone explain what is the reason of this behavior on Java Virtual Machine.

Any help is very appreciated.

Duncan Jones
  • 67,400
  • 29
  • 193
  • 254
aumanets
  • 3,703
  • 8
  • 39
  • 59
  • 2
    possible duplicate of [casting Object array to Integer array error](http://stackoverflow.com/questions/1115230/casting-object-array-to-integer-array-error) – Nishant Apr 09 '11 at 16:49
  • 4
    By the way, the number 3.14 is not an integer. – Alex Apr 09 '11 at 17:07
  • I moved your solution out of your question into a community-wiki [answer below](http://stackoverflow.com/a/25309047/474189). If you'd like to post that answer yourself, to earn some reputation, please let me know and I'll delete the CW one. – Duncan Jones Aug 14 '14 at 13:20
  • possible duplicate of: http://stackoverflow.com/questions/3770289/converting-array-of-primitives-to-array-of-containers-in-java – Ciro Santilli OurBigBook.com Mar 13 '15 at 07:38

11 Answers11

36

Here is a simple one-liner:

Double[] objects = ArrayUtils.toObject(primitives);

You will need to import Apache commons-lang3:

import org.apache.commons.lang3.ArrayUtils;
Datageek
  • 25,977
  • 6
  • 66
  • 70
35

In Java, primitive types and reference types are two distinct worlds. This reflects to arrays: A primitive array is not an object array, that's why you can't cast.

Here is a simpler version of your solution in the question:

private Object[] getArray(Object val){
    if (val instanceof Object[])
       return (Object[])val;
    int arrlength = Array.getLength(val);
    Object[] outputArray = new Object[arrlength];
    for(int i = 0; i < arrlength; ++i){
       outputArray[i] = Array.get(val, i);
    }
    return outputArray;
}

This will still work when they sometimes decide to add new primitive types to the VM.

Of course, you might want to do the copying always, not only in the primitive case, then it gets even simpler:

private Object[] getArray(Object val){
    int arrlength = Array.getLength(val);
    Object[] outputArray = new Object[arrlength];
    for(int i = 0; i < arrlength; ++i){
       outputArray[i] = Array.get(val, i);
    }
    return outputArray;
}

Of course, this is not casting, but converting.

Paŭlo Ebermann
  • 73,284
  • 20
  • 146
  • 210
  • 2
    `Array.getLength` and `get` was just what I needed. So much cleaner code than checking if the array is of a given primitive type and then casting to that. Thanks! – Jan Aagaard Meier Apr 16 '13 at 12:56
7

Originally posted by the OP within the question itself, but pulled here as a separate answer.


After getting response from StKiller and other users I was able to create a more generic method, which is located below:

private final Class<?>[] ARRAY_PRIMITIVE_TYPES = { 
        int[].class, float[].class, double[].class, boolean[].class, 
        byte[].class, short[].class, long[].class, char[].class };

private Object[] getArray(Object val){
    Class<?> valKlass = val.getClass();
    Object[] outputArray = null;

    for(Class<?> arrKlass : ARRAY_PRIMITIVE_TYPES){
        if(valKlass.isAssignableFrom(arrKlass)){
            int arrlength = Array.getLength(val);
            outputArray = new Object[arrlength];
            for(int i = 0; i < arrlength; ++i){
                outputArray[i] = Array.get(val, i);
                            }
            break;
        }
    }
    if(outputArray == null) // not primitive type array
        outputArray = (Object[])val;

    return outputArray;
}

You can pass kind of array into getArray method, which will return Object[] without throwing ClassCastException.

Thanks again for all your replies.

Duncan Jones
  • 67,400
  • 29
  • 193
  • 254
6

Primitive type cannot be transformed in this way. In your case, there is an array of double values, cause of 3.14. This will work:

    List<Object> objectList = new ArrayList<Object>();
    objectList.addAll(Arrays.asList(0,1,2,3.14,4));

Even this works :

List<Object> objectList = new ArrayList<Object>();
objectList.addAll(Arrays.asList(0,"sfsd",2,3.14,new Regexp("Test")));
for(Object object:objectList)
{
    System.out.println(object);
}

UPDATE Ok, there as there was said, there is not direct way to cast a primitive array to an Object[]. If you want a method that transforms any array in String, I can suggest this way

public class CastArray {

    public static void main(String[] args) {
        CastArray test = new CastArray();
        test.TestObj(new int[]{1, 2, 4});
        test.TestObj(new char[]{'c', 'a', 'a'});
        test.TestObj(new String[]{"fdsa", "fdafds"});
    }

    public void TestObj(Object obj) {
        if (!(obj instanceof Object[])) {
            if (obj instanceof int[]) {
                for (int i : (int[]) obj) {
                    System.out.print(i + " ");
                }
                System.out.println("");
            }
            if (obj instanceof char[]) {
                for (char c : (char[]) obj) {
                    System.out.print(c + " ");
                }
                System.out.println("");
            }
            //and so on, for every primitive type.
        } else {
            System.out.println(Arrays.asList((Object[]) obj));
        }
    }
}

Yes, it's annoying to write a loop for every primitive type, but there is no other way, IMHO.

StKiller
  • 7,631
  • 10
  • 43
  • 56
  • But my method receives object, and I don't know what kind of object user has passed. Using reflection I can detect if it as an Array and then cast it to **Object[]**. Is there any workaround? – aumanets Apr 09 '11 at 17:55
  • I thought there was a more organized way to write this code, more "generic". Thanks. – aumanets Apr 09 '11 at 19:54
2

As the original poster first stated in his question:

I have a method that receives an object and then represents it as a string

While the intent was to output an Object's value in a friendly way, he was using Casting as a mean to that end. Therefore, expanding upon Paŭlo Ebermann's answer, here is my solution to make most objects toString() friendly.

The main problem being arrays, it will recursively transform any array X[] into its Object equivalent of List<X>, whether X is a primitive or not. The rest is be handled by each specific object's toString() if needed, as it should.

Important caveat: it is assumed that there are no circular references!

Given:

System.out.println(objectify(new double[][]{{65.5 * 15.9, 0}, {0.123456, 1}}))

The expected result is:

[[1041.45, 0.0], [0.123456, 1.0]]

The implementation:

public Object objectify(Object obj) {
    if(obj == null)
        return obj;
    Object o = obj;
    if(obj.getClass().isArray()) {
        // array
        if(obj instanceof Object[]) {
            // array of Object
            Object[] oI = (Object[])obj;
            Object[] oO = new Object[oI.length];
            for(int i = 0; i < oI.length; i++) {
                // objectify elements
                oO[i] = objectify(oI[i]);
            }
            o = Arrays.asList(oO);
        } else {
            // array of primitive
            int len = Array.getLength(obj);
            Object[] out = new Object[len];
            for(int i = 0; i < len; i++)
                out[i] = Array.get(obj, i);
            o = Arrays.asList(out);
        }
    }
    return o;
}
2

With Java 8 you could use Streams with a mapping function to turn the array into one of any other type like this:

Foo[] fooArray = ...;
Bar[] barArray = Arrays.stream(fooArray).map(object -> (Bar) object).toArray();

Assuming that the given object is assignable to the type you are casting it into. In your case you could turn an Integer array into an object array slightly differently as an integer stream has a different way of mapping objects:

Arrays.stream(intArray).mapToObj(i -> (Object) i).toArray();
Redmatters
  • 41
  • 1
  • 6
  • 2
    Here's another very similar method that I found to be a bit cleaner: `Arrays.stream(intArray).boxed().toArray();` – Flaom Jul 11 '18 at 01:25
  • 3
    Better yet, if you want an array of e.g. `Integer`, rather than a generic `Object` array: `Arrays.stream(intArray).boxed().toArray(Integer[]::new);` – Lambart Sep 23 '19 at 22:05
1

Another implementation for the getArray function with flexible handling of primitive types :

public static Object[] createArrayFromArrayObject(Object o) throws XYZException {
    if(!o.getClass().isArray())
        throw new XYZException("parameter is not an array");

    if(!o.getClass().getComponentType().isPrimitive())
        return (Object[])o;

    int element_count = Array.getLength(o);
    Object elements[] = new Object[element_count];

    for(int i = 0; i < element_count; i++){
        elements[i] = Array.get(o, i);          
    }

    return elements;
}
Hajo Thelen
  • 1,095
  • 1
  • 11
  • 16
0

You could do:

int[] intArray = new int[]{0,1,2,3,14,4};
ArrayList<MyObject> myObjArray = new ArrayList<MyObject>;

for (int i = 0; i < intArray.length; i++) {
myObjArray.set(new MyObject(intArray[i]));
}

You'd need to define a class where the constructor sets the integer parameter to an instance field (in the MyObject class).

Alex
  • 4,844
  • 7
  • 44
  • 58
0

You can only cast an object of type derived type, which is handled and passed as base type. In the opposite direction, you can just assign a derived type to a base type:

Object o = new String ("simple assignment");
String s = (String) o; 

There in no transformation of the Object going on - it is just demasked as what it is, what it always was.

Integer [] ia = new Integer [] {4, 2, 6};
Object  [] oa = ia;     

But primitive ints aren't Objects, hence they can't be assigned to an Object array. Casting, however, would, if possible, only play a role in the opposite direction.

user unknown
  • 35,537
  • 11
  • 75
  • 121
0

None of the answers presented here work with multidimensional arrays, so here's my universal wrapper. It works with arrays of any type and any dimension, and also correctly handles null references (including deeply hidden ones).

import java.lang.reflect.Array;
import java.util.Arrays;

public class ArrayWrapper {
    private static Object[] deepWrap(Class<?> componentClass, Object a) {
        if (a == null)
            return null;
        Object[] result = (Object[])Array.newInstance(componentClass, Array.getLength(a));
        if (componentClass.isArray()) {
            Class<?> innerCompClass = componentClass.getComponentType();
            Object[] b = (Object[])a;
            Arrays.parallelSetAll(result, i -> deepWrap(innerCompClass, b[i]));
        } else
            Arrays.setAll(result, i -> Array.get(a, i));
        return result;
    }

    public static Object[] wrap(Object a) {
        if (a == null)
            return null;
        Class<?> c = a.getClass();
        if (!c.isArray())
            throw new IllegalArgumentException("Not an array");
        int dimension = 0;
        do {
            dimension++;
            c = c.getComponentType();
        } while (c.isArray());
        if (!c.isPrimitive())
            return (Object[])a;
        c = Array.get(Array.newInstance(c, 1), 0).getClass();
        while (--dimension > 0)
            c = Array.newInstance(c, 0).getClass();
        return deepWrap(c, a);
    }
}

Usage demo:

public static void main(String[] args) {
    final int size1 = 5;
    final int size2 = 4;
    int[][] b = new int[size1][size2];
    for (int i = 0; i < size1; i++)
        for (int j = 0; j < size2; j++)
            b[i][j] = (i + 1) * (j + 1);
    b[1] = new int[7];
    b[1][4] = 4;
    b[3] = null;
    System.out.println(b.getClass().getCanonicalName());
    System.out.println(Arrays.deepToString(b));
    Integer[][] w = (Integer[][])wrap(b);
    System.out.println(w.getClass().getCanonicalName());
    System.out.println(Arrays.deepToString(w));
}
John McClane
  • 3,498
  • 3
  • 12
  • 33
-2

Primitive types are not Objects. There is no workaround, you can cast any arrays that contain objects to Object[], but not arrays that contain primitive types.

Ingo
  • 36,037
  • 5
  • 53
  • 100
  • You can't cast directly but if you know what data to expect you can create new classes to accomodate that accordingly. – Alex Apr 09 '11 at 16:58
  • Sure, but then its not casting anymore. – Ingo Apr 09 '11 at 17:02
  • You said "there's no workaround", I'm just saying... there's always a workaround. – Alex Apr 09 '11 at 17:04
  • You can't caste an int to an Object, thats the issue. Not int to Integer. Simple solution, use Java classes. Way more preferable for design taking whole blocks of data into an object. – Alex Apr 09 '11 at 17:47
  • @Ingo: You don't cast arrays that contain something, derived from Object to Object[] - you just assign them. Casting only takes place in the opposite direction. – user unknown Apr 09 '11 at 17:58
  • @unknown user - I don't do that, that's right, but obviously StKiller does, otherwise he did not get a ClassCastException. To be more precise, I refer to the syntactic form *(Type) expression* as a cast, hence (Object) "xy" is syntactically a cast even if "xy" is already an object. You wouldn't deny that 5+0 is an addition, would you? – Ingo Apr 09 '11 at 19:43