Cast primitive type array into object array in jav

2020-01-29 05:22发布

问题:

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.

回答1:

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.



回答2:

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;


回答3:

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.



回答4:

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.



回答5:

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


回答6:

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


回答7:

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



回答8:

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.



回答9:

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


回答10:

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.