web-dev-qa-db-ger.com

Umwandeln eines primitiven Typ-Arrays in ein Object-Array in Java

Warum kann ich das nicht in Java machen?

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

Ich habe eine Methode, die ein Objekt empfängt und es dann als String darstellt, aber abhängig von seinem Typ (primitiv, primitiver Wrapper, Array usw.). Beim Erstellen eines Unit-Tests habe ich ein Array als Object übergeben, was in Ordnung ist, aber wenn ich dieses Objekt in Object [] konvertiere, bekomme ich ClassCastException . Dies geschieht nur bei Arrays vom primitiven Typ. Gibt es eine Möglichkeit, dieses Verhalten zu vermeiden? Wenn nicht, kann jemand erklären, warum dies auf Java Virtual Machine der Grund ist.

Jede Hilfe wird sehr geschätzt.

28
aumanets

Der Primitivtyp kann nicht auf diese Weise transformiert werden .. In Ihrem Fall gibt es ein Array von doppelten Werten, Ursache von 3.14 .. Dies wird funktionieren:

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

Auch das funktioniert:

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, da gab es keine direkte Möglichkeit, ein primitives Array in ein Object [] umzuwandeln. Wenn Sie eine Methode wünschen, die ein Array in String umwandelt, kann ich dies vorschlagen

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

Ja, es ist ärgerlich, für jeden primitiven Typ eine Schleife zu schreiben, aber es gibt keinen anderen Weg, IMHO. 

7
StKiller

Hier ist ein einfacher Einzeiler:

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

Sie müssen Apache commons-lang3 importieren:

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

In Java sind primitive Typen und Referenztypen zwei verschiedene Welten. Dies gilt für Arrays: Ein primitives Array ist kein Objektarray, deshalb können Sie es nicht umsetzen.

Hier ist eine einfachere Version Ihrer Lösung in der Frage:

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

Dies funktioniert auch dann, wenn sie manchmal beschließen, der VM neue primitive Typen hinzuzufügen.

Natürlich möchten Sie das Kopieren immer durchführen, nicht nur im primitiven Fall. Dann wird es noch einfacher:

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

Das ist natürlich kein Casting, sondern Converting.

29
Paŭlo Ebermann

Ursprünglich vom OP in der Frage selbst gepostet, aber hier als separate Antwort gezogen.


Nach der Antwort von StKiller und anderen Benutzern Ich konnte eine allgemeinere Methode erstellen, die sich unten befindet:

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

Sie können eine Art Array an die getArray-Methode übergeben, die Object [] zurückgibt, ohne ClassCastException auszulösen.

Nochmals vielen Dank für alle Ihre Antworten.

4
Duncan Jones

Eine weitere Implementierung für die getArray-Funktion mit flexibler Handhabung von primitiven Typen:

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

Wie das ursprüngliche Plakat in seiner Frage zum ersten Mal feststellte:

Ich habe eine Methode, die ein Objekt empfängt und es dann als String darstellt

Während die Absicht war, den Wert eines Object auf freundliche Weise auszugeben, verwendete er Casting zu diesem Zweck als mean. Ausgehend von der Antwort von Paŭlo Ebermann ist hier meine Lösung, um die meisten Objekte toString() freundlich zu gestalten.

Das Hauptproblem bei Arrays besteht darin, dass jedes Array X[] rekursiv in sein Object-Äquivalent zu List<X> umgewandelt wird, unabhängig davon, ob X ein Primitiv ist oder nicht. Der Rest wird von toString() jedes bestimmten Objekts nach Bedarf behandelt.

Wichtiger Hinweis: Es wird davon ausgegangen, dass es keine Zirkelverweise gibt!

Gegeben :

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

Das erwartete Ergebnis ist :

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

Die Umsetzung :

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

Sie können nur ein Objekt vom Typ abgeleiteter Typ umwandeln, der als Basistyp behandelt und übergeben wird. In umgekehrter Richtung können Sie einem Basistyp einfach einen abgeleiteten Typ zuweisen: 

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

Es findet keine Transformation des Objekts statt - es wird nur als das entlarvt, was es ist, was es immer war. 

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

primitive ints sind jedoch keine Objekte, daher können sie nicht einem Object-Array zugewiesen werden. Casting würde jedoch, wenn möglich, nur in die entgegengesetzte Richtung eine Rolle spielen.

0
user unknown

Mit Java 8 können Sie Streams mit einer Mapping-Funktion verwenden, um das Array in einen beliebigen anderen Typ zu verwandeln:

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

Angenommen, das angegebene Objekt kann dem Typ zugewiesen werden, in den Sie es werfen. In Ihrem Fall können Sie ein Integer-Array etwas anders in ein Objekt-Array umwandeln, da ein Integer-Stream eine andere Art hat, Objekte abzubilden:

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

Primitive Typen sind keine Objekte. Es gibt keine Problemumgehung. Sie können Arrays, die Objekte enthalten, in Object [] umwandeln, jedoch keine Arrays, die primitive Typen enthalten.

0
Ingo

Du könntest es tun:

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

Sie müssten eine Klasse definieren, in der der Konstruktor den Integer-Parameter auf ein Instanzfeld (in der MyObject-Klasse) setzt.

0
Alex