web-dev-qa-db-ja.com

javaのプリミティブ型配列をオブジェクト配列にキャストします

Javaでこれができないのはなぜですか?

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

オブジェクトを受け取り、それを文字列として表すメソッドがありますが、そのタイプ(プリミティブ、プリミティブラッパー、配列など)に依存します。ユニットテストを作成していたとき、配列をObjectとして渡していましたが、これはそのオブジェクトをObject []にキャストすると実行されます- ClassCastException。これは、プリミティブ型の配列でのみ発生します。この動作を回避する方法はありますか?そうでない場合、誰かがJava Virtual Machine。

どんな助けも大歓迎です。

30
aumanets

プリミティブ型はこの方法で変換できません。あなたの場合、3.14の原因であるdouble値の配列があります。これは動作します:

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

はい、すべてのプリミティブ型に対してループを記述するのは面倒ですが、他に方法はありません。

7
StKiller

シンプルなワンライナーは次のとおりです。

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

インポートする必要があります Apache commons-lang

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

Javaでは、プリミティブ型と参照型は2つの異なる世界です。これは配列に反映されます。プリミティブ配列はオブジェクト配列ではないため、キャストできません。

問題のソリューションのよりシンプルなバージョンを次に示します。

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

VMに新しいプリミティブタイプを追加する場合がある場合でも、これは機能します。

もちろん、プリミティブな場合だけでなく、常にコピーを行いたい場合は、さらに簡単になります。

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
Paŭlo Ebermann

元々は質問自体の中でOPによって投稿されましたが、ここでは別の回答として引き出されました。


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メソッドに渡すと、ClassCastExceptionをスローせずにObject []を返します。

返信ありがとうございます。

4
Duncan Jones

プリミティブ型を柔軟に処理する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;
}
2
Hajo Thelen

元のポスターが彼の質問で最初に述べたように:

オブジェクトを受け取り、それを文字列として表すメソッドがあります

意図はObjectの値をわかりやすい方法で出力することでしたが、彼はそのためにmeanとしてキャストを使用していました。したがって、PaŭloEbermannの答えを拡張すると、ほとんどのオブジェクトをtoString()フレンドリーにするための私のソリューションが得られます。

配列の主な問題は、Xがプリミティブであるかどうかにかかわらず、配列_X[]_を_List<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

ベース型として処理および渡される型派生型のオブジェクトのみをキャストできます。逆方向では、派生型を基本型に割り当てることができます。

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

オブジェクトの変換は行われていません。それは、それが何であるか、常に何であったかとして単にマスク解除されています。

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

しかし、primitive intsはオブジェクトではないため、Object配列に割り当てることはできません。ただし、キャスティングは、可能であれば、反対方向にのみ機能します。

0
user unknown

Java 8を使用すると、Streamsとマッピング関数を使用して、配列を次のような他のタイプのいずれかに変換できます。

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

指定されたオブジェクトは、キャスト先の型に割り当て可能であると想定しています。あなたの場合、整数ストリームはオブジェクトのマッピング方法が異なるため、整数配列をオブジェクト配列にわずかに変えることができます:

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

プリミティブ型はオブジェクトではありません。回避策はありません。オブジェクトを含む配列をObject []にキャストできますが、プリミティブ型を含む配列はキャストできません。

0
Ingo

できること:

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
Alex