简体   繁体   English

在java中将原始类型数组转换为对象数组

[英]Cast primitive type array into object array in java

Why I cannot do this in java?为什么我不能在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 .当我创建一个单元测试时,我将一个数组作为Object传递,这是好的,但是当我将该对象强制转换为Object[] 时,我得到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.如果没有,有人可以解释 Java 虚拟机上这种行为的原因是什么。

Any help is very appreciated.非常感谢任何帮助。

Here is a simple one-liner:这是一个简单的单行:

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

You will need to import Apache commons-lang3 :您将需要导入Apache commons-lang3

import org.apache.commons.lang3.ArrayUtils;

In Java, primitive types and reference types are two distinct worlds.在 Java 中,原始类型和引用类型是两个截然不同的世界。 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.当他们有时决定向 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 .当然,这不是强制转换,而是转换.

Originally posted by the OP within the question itself, but pulled here as a separate answer.最初由 OP 在问题本身中发布,但作为单独的答案拉到这里。


After getting response from StKiller and other users I was able to create a more generic method, which is located below:在得到 StKiller 和其他用户的响应后,我能够创建一个更通用的方法,它位于下面:

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.您可以将数组类型传递给 getArray 方法,该方法将返回Object[]而不抛出 ClassCastException。

Thanks again for all your replies.再次感谢您的所有回复。

Primitive type cannot be transformed in this way.原始类型不能以这种方式转换。 In your case, there is an array of double values, cause of 3.14.在您的情况下,有一个 double 值数组,原因为 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[].更新好的,正如前面所说,没有直接的方法可以将原始数组转换为 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.是的,为每个原始类型编写一个循环很烦人,但没有其他方法,恕我直言。

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.虽然目的是为了输出Object以友好的方式的价值,他是用铸造的平均实现这一目标。 Therefore, expanding upon Paŭlo Ebermann 's answer, here is my solution to make most objects toString() friendly.因此,扩展Paŭlo Ebermann的答案,这是我使大多数对象toString()友好的解决方案。

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.主要问题是数组,它会递归地将任何数组X[]转换为List<X> Object 等价物,无论X是否为原始数组。 The rest is be handled by each specific object's toString() if needed, as it should.如果需要,其余的由每个特定对象的toString()处理,因为它应该。

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

With Java 8 you could use Streams with a mapping function to turn the array into one of any other type like this:使用 Java 8,您可以使用带有映射函数的 Streams 将数组转换为任何其他类型之一,如下所示:

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:在您的情况下,您可以将一个 Integer 数组转换为一个稍微不同的对象数组,因为整数流具有不同的映射对象方式:

Arrays.stream(intArray).mapToObj(i -> (Object) i).toArray();

Another implementation for the getArray function with flexible handling of primitive types :灵活处理原始类型的 getArray 函数的另一种实现:

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

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).您需要定义一个类,其中构造函数将整数参数设置为实例字段(在 MyObject 类中)。

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.然而,如果可能的话,铸造只会在相反的方向发挥作用。

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

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.没有解决方法,您可以将包含对象的任何数组强制转换为 Object[],但不能将包含基本类型的数组强制转换。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM