Привести массив примитивных типов в массив объектов в Java - PullRequest
30 голосов
/ 09 апреля 2011

Почему я не могу сделать это в Java?

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

У меня есть метод, который получает объект и затем представляет его как строку, но в зависимости от его типа (примитив, примитивная оболочка, массив и т. Д.). Когда я создавал модульный тест, я передавал массив как Object , что нормально, но когда я выполняю приведение этого объекта в Object [] , я получаю ClassCastException . Это происходит только с массивами примитивного типа. Есть ли способ избежать такого поведения? Если нет, может кто-нибудь объяснить, в чем причина такого поведения на виртуальной машине Java.

Любая помощь очень ценится.

Ответы [ 10 ]

30 голосов
/ 10 апреля 2011

В Java примитивные типы и ссылочные типы - это два разных мира.Это отражается на массивах: примитивный массив не является массивом объектов, поэтому вы не можете приводить.

Вот более простая версия вашего решения в вопросе:

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

Этобудет по-прежнему работать, когда они иногда решат добавить новые типы примитивов в ВМ.

Конечно, вы можете захотеть делать копирование всегда, не только в примитивном случае, тогда это становится еще проще:

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

Конечно, это не кастинг, а конвертирование .

30 голосов
/ 23 апреля 2015

Вот простой однострочный:

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

Вам нужно будет импортировать Apache commons-lang3 :

import org.apache.commons.lang3.ArrayUtils;
7 голосов
/ 09 апреля 2011

Примитивный тип не может быть преобразован таким образом. В вашем случае есть массив двойных значений, причина 3.14. Это будет работать:

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

Даже это работает:

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 Хорошо, там, как уже было сказано, нет прямого способа привести массив примитивов к Object []. Если вам нужен метод, который преобразует любой массив в String, я могу предложить этот способ

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

Да, раздражает писать цикл для каждого примитивного типа, но другого пути нет, ИМХО.

4 голосов
/ 14 августа 2014

Первоначально опубликовано ФП в самом вопросе, но приведено здесь как отдельный ответ.


После получения ответа от 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;
}

Вы можете передать вид массива в метод getArray, который вернет Object [] без выброса ClassCastException.

Еще раз спасибо за все ваши ответы.

2 голосов
/ 21 июня 2011

Еще одна реализация функции 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;
}
0 голосов
/ 22 июля 2017

В Java 8 вы можете использовать Streams с функцией отображения, чтобы превратить массив в любой другой тип, подобный этому:

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

Предполагая, что данный объект присваивается типу, в который вы его приводите. В вашем случае вы можете превратить массив Integer в массив объектов немного по-другому, поскольку поток целых чисел имеет другой способ отображения объектов:

Arrays.stream(intArray).mapToObj(i -> (Object) i).toArray();
0 голосов
/ 30 сентября 2014

Как первый автор в своем вопросе впервые заявил:

У меня есть метод, который получает объект, а затем представляет его в виде строки

Хотя намерение былочтобы вывести значение Object дружественным образом, он использовал Casting как среднее для этой цели.Поэтому, развивая ответ Paŭlo Ebermann , я предлагаю решение, которое сделает большинство объектов toString() дружественными.

Основная проблема, связанная с массивами, будет рекурсивно преобразовывать любой массив X[]в его объектный эквивалент List<X>, является ли X примитивом или нет.Все остальное обрабатывается toString() каждого конкретного объекта, если это необходимо, как и должно быть.

Важное предупреждение: предполагается, что циклические ссылки отсутствуют!

Учитывая :

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

Ожидаемый результат: :

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

Реализация :

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;
}
0 голосов
/ 09 апреля 2011

Вы можете приводить только объект типа производного типа, который обрабатывается и передается как базовый тип.В обратном направлении вы можете просто назначить производный тип базовому типу:

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

Там не происходит никакого преобразования Объекта - он просто демаскируется как то, что есть, каким оно всегда было.

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

Но примитивы не являются объектами, поэтому их нельзя назначить массиву объектов.Однако литье, по возможности, будет играть роль только в противоположном направлении.

0 голосов
/ 09 апреля 2011

Вы можете сделать:

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

Вам необходимо определить класс, в котором конструктор устанавливает целочисленный параметр для поля экземпляра (в классе MyObject).

0 голосов
/ 09 апреля 2011

Примитивные типы не являются объектами.Обходного пути нет, вы можете приводить любые массивы, содержащие объекты, в Object [], но не массивы, содержащие примитивные типы.

...