web-dev-qa-db-fra.com

Couler un tableau de type primitif dans un tableau d'objets en java

Pourquoi je ne peux pas faire ça en Java?

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

J'ai une méthode qui reçoit un objet et le représente ensuite comme une chaîne, mais en fonction de son type (primitive, wrapper primitive, tableau, etc ...). Lorsque je créais un test unitaire, je passais un tableau sous la forme Object , ce qui est correct, mais lorsque j'effectue la conversion de cet objet dans Object [] j'obtiens ClassCastException . Cela ne se produit qu'avec des tableaux de types primitifs. Y a-t-il un moyen d'éviter ce comportement? Sinon, quelqu'un pourrait-il expliquer quelle est la raison de ce comportement sur Java Virtual Machine.

Toute aide est très appréciée.

28
aumanets

Le type primitif ne peut pas être transformé de cette façon . Dans votre cas, il existe un tableau de valeurs doubles, cause de 3.14 . Cela fonctionnera:

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

Même cela fonctionne:

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, comme il a été dit, il n’existe pas de moyen direct de convertir un tableau primitif en Object []. Si vous voulez une méthode qui transforme n'importe quel tableau en String, je peux suggérer ceci

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

Oui, il est embêtant d'écrire une boucle pour chaque type de primitive, mais il n'y a pas d'autre moyen, à mon humble avis. 

7
StKiller

Voici un one-liner simple:

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

Vous devrez importer Apache commons-lang3 :

import org.Apache.commons.lang3.ArrayUtils;
30
Datageek

En Java, les types primitifs et les types de référence sont deux mondes distincts. Cela reflète les tableaux: Un tableau primitif n'est pas un tableau d'objets, c'est pourquoi vous ne pouvez pas lancer de cast.

Voici une version plus simple de votre solution dans la 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;
}

Cela fonctionnera quand ils décideront parfois d’ajouter de nouveaux types primitifs à la VM.

Bien sûr, vous pouvez toujours faire la copie, pas seulement dans le cas primitif, cela devient encore plus simple:

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

Bien sûr, ce n'est pas un casting, mais une conversion .

29
Paŭlo Ebermann

_ {Publié à l'origine par le PO dans la question elle-même, mais tiré ici en tant que réponse distincte.} _


Après avoir reçu une réponse de StKiller et d’autres utilisateurs .__, j’ai pu créer une méthode plus générique, qui se trouve ci-dessous:

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

Vous pouvez passer genre de tableau dans la méthode getArray, qui renverra Object [] sans lancer ClassCastException.

Merci encore pour toutes vos réponses.

3
Duncan Jones

Une autre implémentation de la fonction getArray avec une gestion flexible des types primitifs:

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;
}
2
Hajo Thelen

Comme l'affiche pour la première fois dans sa question:

J'ai une méthode qui reçoit un objet et le représente ensuite sous forme de chaîne

Bien que l'intention soit de générer une valeur de Object de manière conviviale, il utilisait Casting comme un mean à cette fin. Par conséquent, en développant la réponse de Paŭlo Ebermann , voici ma solution pour rendre la plupart des objets compatibles avec toString().

Le problème principal étant les tableaux, il transformera récursivement tout tableau X[] en son équivalent d'objet de List<X>, que X soit une primitive ou non. Le reste est traité par la fonction toString() de chaque objet spécifique si nécessaire, comme il se doit.

Mise en garde importante: il est supposé qu'il n'y a pas de références circulaires!

Donné :

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

Le résultat attendu est :

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

La mise en oeuvre :

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
Alexandre Delisle

Vous pouvez uniquement transtyper un objet de type dérivé de type, qui est géré et transmis en tant que type de base. Dans le sens opposé, vous pouvez simplement affecter un type dérivé à un type de base: 

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

Il n’ya aucune transformation de l’objet en cours - il est simplement démasqué en tant que tel, ce qu’il a toujours été. 

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

Mais primitive ints ne sont pas des objets et ne peuvent donc pas être affectés à un tableau Object. Toutefois, dans la mesure du possible, le casting ne jouerait qu'un rôle dans la direction opposée.

0
user unknown

Avec Java 8, vous pouvez utiliser Streams avec une fonction de mappage pour transformer le tableau en un type quelconque comme celui-ci:

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

En supposant que l'objet donné puisse être assigné au type dans lequel vous le convertissez. Dans votre cas, vous pouvez transformer un tableau Integer en un tableau d'objets de manière légèrement différente, car un flux entier a une manière différente de mapper des objets:

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

Les types primitifs ne sont pas des objets. Il n'y a pas de solution de contournement. Vous pouvez convertir tous les tableaux contenant des objets en Object [], mais pas les tableaux contenant des types primitifs.

0
Ingo

Vous pourriez faire:

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

Vous devez définir une classe dans laquelle le constructeur définit le paramètre entier comme un champ d'instance (dans la classe MyObject).

0
Alex