3

假设我有一个对象类和一个int[]描述我希望实例化(并使用)的多维数组的任意长度。到目前为止,我已经确定可以使用java.lang.reflect.Array.newInstance(Class<?> type, int... sizes),但那时我被卡住了。换句话说,

Class<?> type = float.class;  // this varies (I receive this)
int[] sizes = new int[]{ 10, 400, 300 }; // this varies too, it could be e.g. int[]{0} for a scalar
Object o = (Object) java.lang.reflect.Array.newInstance(type, sizes);

定义后Object o我不知道如何进行。先验,我不知道是否type会是float.class或其他类型(现在我假设它是基本类型)。更糟糕的是,int[] sizes可以是任何东西。

为了使它成为一个更具体的问题,我应该如何为多维数组的每个元素设置o一个给定的值,比如5.6在我用 实例化它之后Array.newInstance

4

3 回答 3

1

好问题。这真的很棘手,因为似乎没有办法将对象转换为给定维度的数组。我找不到从创建的实例中获取正确的多维数组对象的方法。但是如果你只是想在创建的数组中获取和设置元素,你可以使用下面的方法:

public static void main(String[] args) {
    Class<?> type = float.class; // this varies (I receive this)
    int[] sizes = new int[] { 1, 3 }; // this varies too, it could be e.g.
                                    // int[]{0} for a scalar
    Object f = Array.newInstance(type, sizes);
    set(f, new int[] { 0, 2 }, 3.0f);
    if (f instanceof Object[])
        System.out.println(Arrays.deepToString((Object[]) f));
    else {
        int l = Array.getLength(f);
        for (int i = 0; i < l; ++i) {
            System.out.print(Array.get(f, i) + ", ");
        }
        System.out.println();
    }
}

public static void set(Object arr, int[] indexPath, Object value) {
    if (arr instanceof Object[]) {
        Object[] temp= (Object[]) arr;
        for (int i = 0; i < indexPath.length - 2; ++i) {
            temp = (Object[]) temp[indexPath[i]];
        }
        Array.set(temp[indexPath[indexPath.length - 2]],
            indexPath[indexPath.length - 1], value);
    } else {
        Array.set(arr,
                indexPath[0], value);
    }
}

set方法将索引设置为数组。所以set(f, new int[] {0,0,1}, 3.0f);基本上应该做f[0][0][1] = 3.0f

编辑:添加了一个稍微难看的修复来处理一维数组

于 2013-10-14T11:22:35.390 回答
0

java.lang.reflect.Array类中查看,还有其他有用的方法,例如get(Object array, int index)setFloat(Object array, int index, float f)。使用这些的组合,一个人应该能够填充整个多维数组。

粗略的伪代码:

Object level0 = createArray(...)
For i1 = 0 to (length of dimension 1) {
    Object level1 = get(level0, i1)
    For i2 = 0 to (length of dimension 2) {
        Object level2 = get(level1, i2)
        ...etc...
            For iM = 0 to (length of dimension M) {
                Object levelM = get(levelL, iM)
                For iN = 0 to (length of dimension N) {
                    setFloat(levelM, iN, 5.6f)
                }
            }
        ...
    }
}

如果我正确阅读 API,那么这样的东西应该可以工作。

于 2013-10-14T10:38:23.043 回答
0

I ended up coding the solution instead of attempting to find/use array manipulation methods from the Java API (the only one below is java.util.Arrays.copyOf(Object[], int).

So, below are the methods I wrote. I did not test them extensively (I wouldn't be surprised if there are inefficiencies there, I just tried the first thing that appeared to work), so I expect that the following solution can be adapted to suit others' needs:

/**
 * Creates an instance of Object multi-dimensional arrays, with dimensions specified by the argument.
 * 
 * @example Create an array Object[4][20][30]:  
 * <pre>
 * Object[] array = newArray(new int[]{4,20,30});
 * </pre>
 * 
 * @param sizes The list of dimension lengths.
 * @return 
 */
public static Object[] newArray(int[] sizes) {
    Object[] result = null;
    if (sizes != null) {
        for(int n = sizes.length - 1; n >= 0; n--) {
            if (result == null) {
                result = new Object[sizes[n]];
            } else {
                Object[] oa = new Object[sizes[n]];
                for (int i = 0; i < sizes[n]; i++) {
                    oa[i] = java.util.Arrays.copyOf(result, result.length);
                }
                result = oa;
            }
        }
        if (result == null) { result = new Object[1]; }
    }
    return result;
}

/**
 * Get the value of a multi-dimensional array element given by a coordinate list.
 * 
 * @example Read the value at [2][14][27]:
 * <pre>
 * Object[] array;  // e.g. a int[4][20][30] created with newArray(int[])
 * int[] coord = new int[]{2,14,27};
 * Object value = getValue(array, coord);
 * </pre>
 * 
 * @param array The coordinates of the array element.
 * @param coordinates
 * @return
 */
public static Object getValue(Object[] array, int[] coordinates) {
    Object result = null;
    if (array == null || coordinates == null || 0 > coordinates[0]||coordinates[0] > array.length) {
        result = null;
    } else {
        int x = coordinates[0];
        if (array[x] instanceof Object[]) {
            int[] c = new int[coordinates.length-1];
            for(int i = 0; i < c.length; i++) { c[i] = coordinates[i + 1]; }
            result = getValue((Object[]) array[x], c);
        } else {
            result = array[x];
        }
    }
    return result;
}

/**
 * Set the value of a multi-dimensional array element given a list designating the element's coordinates.
 * 
 * @example Write a value to [1][0][7]:
 * <pre>
 * Object value;    // e.g. a float
 * Object[] array;  // e.g. a int[4][20][30] created with newArray(int[])
 * int[] coord = new int[]{1,0,7,};
 * setValue(array, coord, value);
 * </pre>
 * 
 * @param array
 * @param coordinates
 * @param value
 * @return
 */
public static void setValue(Object[] array, int[] coordinates, Object value) {
    if (array == null || coordinates == null || array.length == 0 || coordinates.length == 0 || array.length < coordinates[0]||coordinates[0] < 0 ) {
        return;
    } else {
        int x = coordinates[0];
        if (array[x] != null && array[x].getClass().isArray()) {    // recurse
            int[] c = new int[coordinates.length - 1];
            for (int i = 0; i < c.length; i++) { c[i] = coordinates[i + 1]; }
            setValue((Object[]) array[x], c, value); 
        } else {
            array[x] = value;
        }
    }
    return;
}
于 2013-10-14T17:06:47.727 回答