是否可以在Java中动态构建多维数组?

假设我们有Java代码:

Object arr = Array.newInstance(Array.class, 5); 

那会跑吗? 作为进一步的说明,如果我们尝试这样的事情怎么办:

 Object arr1 = Array.newInstance(Array.class, 2); Object arr2 = Array.newInstance(String.class, 4); Object arr3 = Array.newInstance(String.class, 4); Array.set(arr1, 0, arr2); Array.set(arr1, 1, arr3); 

那么arr1会是一个2D数组,相当于:

 String[2][4] arr1; 

怎么样:如果我们在运行时之前不知道这个数组的大小怎么办?

编辑:如果这有帮助(我相信它会…)我们试图从表单的字符串解析未知维度的数组

 [value1, value2, ...] 

要么

 [ [value11, value12, ...] [value21, value22, ...] ...] 

等等

编辑2:如果有人像我一样愚蠢尝试这个垃圾,这里是一个至少编译和运行的版本。 逻辑是否合理完全是另一个问题……

 Object arr1 = Array.newInstance(Object.class, x); Object arr11 = Array.newInstance(Object.class, y); Object arr12 = Array.newInstance(Object.class, y); ... Object arr1x = Array.newInstance(Object.class, y); Array.set(arr1, 0, arr11); Array.set(arr1, 1, arr12); ... Array.set(arr1, x-1, arr1x); 

等等。 它只需要是一个巨大的嵌套对象数组

实际上可以用java做。 (我必须说,我有点惊讶。)

免责声明; 我从来没有想过在其他任何地方看到这个代码而不是这个问题的答案。 我强烈建议您使用List

 import java.lang.reflect.Array; import java.util.*; public class Test { public static int[] tail(int[] arr) { return Arrays.copyOfRange(arr, 1, arr.length); } public static void setValue(Object array, String value, int... indecies) { if (indecies.length == 1) ((String[]) array)[indecies[0]] = value; else setValue(Array.get(array, indecies[0]), value, tail(indecies)); } public static void fillWithSomeValues(Object array, String v, int... sizes) { for (int i = 0; i < sizes[0]; i++) if (sizes.length == 1) ((String[]) array)[i] = v + i; else fillWithSomeValues(Array.get(array, i), v + i, tail(sizes)); } public static void main(String[] args) { // Randomly choose number of dimensions (1, 2 or 3) at runtime. Random r = new Random(); int dims = 1 + r.nextInt(3); // Randomly choose array lengths (1, 2 or 3) at runtime. int[] sizes = new int[dims]; for (int i = 0; i < sizes.length; i++) sizes[i] = 1 + r.nextInt(3); // Create array System.out.println("Creating array with dimensions / sizes: " + Arrays.toString(sizes).replaceAll(", ", "][")); Object multiDimArray = Array.newInstance(String.class, sizes); // Fill with some fillWithSomeValues(multiDimArray, "pos ", sizes); System.out.println(Arrays.deepToString((Object[]) multiDimArray)); } } 

示例输出:

 Creating array with dimensions / sizes: [2][3][2] [[[pos 000, pos 001], [pos 010, pos 011], [pos 020, pos 021]], [[pos 100, pos 101], [pos 110, pos 111], [pos 120, pos 121]]] 

数组在java中是类型安全的 – 适用于简单数组和“多维”数组 – 即数组数组。

如果嵌套的深度在运行时是可变的,那么你可以做的最好的事情就是使用一个与已知的最小嵌套深度相对应的数组(大概是1)。这个数组中的元素可以是简单元素,也可以是进一步嵌套是必需的,另一个arrays。 Object []数组将允许您执行此操作,因为嵌套数组本身也被视为对象,因此适合类型系统。

如果嵌套是完全规则的,那么你可以使用Array.newInstance(String.class, dimension1, dimension2, ...)来抢占这种规律并创建一个合适的多维数组,如果嵌套是不规则的,你最好使用嵌套列表,允许“锯齿状”结构和动态大小。 在generics的基础上,你可以有一个锯齿状的结构。 如果结构是锯齿状的,则不能使用generics,因为某些元素可能是简单的项目,而其他元素可能是进一步嵌套的列表。

因此,您可以将多个维度传递给Array.newInstance ,但这会强制每个维度固定长度。 如果没关系,可以使用:

 // We already know from scanning the input that we need a 2 x 4 array. // Obviously this array would be created some other way. Probably through // a List.toArray operation. final int[] dimensions = new int[2]; dimensions[0] = 2; dimensions[1] = 4; // Create the array, giving the dimensions as the second input. Object array = Array.newInstance(String.class, dimensions); // At this point, array is a String[2][4]. // It looks like this, when the first dimension is output: // [[Ljava.lang.String;@3e25a5, [Ljava.lang.String;@19821f] // // The second dimensions look like this: // [null, null, null, null] 

另一种选择是从底部构建它们,使用前一级数组上的getClass作为下一级别的输入。 以下代码运行并生成由节点定义的锯齿状数组:

 import java.lang.reflect.Array; public class DynamicArrayTest { private static class Node { public java.util.List children = new java.util.LinkedList(); public int length = 0; } public static void main(String[] args) { Node node1 = new Node(); node1.length = 1; Node node2 = new Node(); node2.length = 2; Node node3 = new Node(); node3.length = 3; Node node4 = new Node(); node4.children.add(node1); node4.children.add(node2); Node node5 = new Node(); node5.children.add(node3); Node node6 = new Node(); node6.children.add(node4); node6.children.add(node5); Object array = createArray(String.class, node6); outputArray(array); System.out.println(); } private static Object createArray(Class type, Node root) { if (root.length != 0) { return Array.newInstance(type, root.length); } else { java.util.List children = new java.util.ArrayList(root.children.size()); for(Node child : root.children) { children.add(createArray(type, child)); } Object array = Array.newInstance(children.get(0).getClass(), children.size()); for(int i = 0; i < Array.getLength(array); ++i) { Array.set(array, i, children.get(i)); } return array; } } private static void outputArray(Object array) { System.out.print("[ "); for(int i = 0; i < Array.getLength(array); ++i) { Object element = Array.get(array, i); if (element != null && element.getClass().isArray()) outputArray(element); else System.out.print(element); System.out.print(", "); } System.out.print("]"); } } 

作为进一步的说明,如果我们尝试这样的事情怎么办:

 Object arr1 = Array.newInstance(Array.class, 2); Object arr2 = Array.newInstance(String.class, 4); Object arr3 = Array.newInstance(String.class, 4); Array.set(arr1, 0, arr2); ... 

不,你不能像这样设置String[]值。 你遇到了

 Exception in thread "main" java.lang.IllegalArgumentException: array element type mismatch at java.lang.reflect.Array.set(Native Method) at Test.main(Test.java:12) 

好的,如果您不确定数组的尺寸,则以下方法将不起作用。 但是,如果您确实知道尺寸,请不要使用reflection。 请执行下列操作:

您可以比这更容易地动态构建2darrays。

 int x = //some value int y = //some other value String[][] arr = new String[x][y]; 

这将“动态”创建一个xy 2d数组。

有效的Java项目#( 我不记得了 ):了解并使用这些库。

您可以使用List并使用toArray方法:

 List twoDimension = new ArrayList(); 

要将其转换为数组,您可以使用:

 String [][] theArray = twoDimension.toArray( new String[twoDimension.size()][] ); 

诀窍是,外部数组被声明为包含String[] (字符串数组),而后者又可以使用另一个List动态创建,或者,如果您使用String.split方法解析字符串。

演示

关注数组的动态创建而不是解析,这里有一个关于它如何与String.split结合使用的示例

 // and array which contains N elements of M size String input = "[[1],[2,3],[4,5,6,7],[8,9,10,11,12,13]]"; // Declare your dynamic array List multiDimArray = new ArrayList(); // split where ],[ is found, just ignore the leading [[ and the trailing ]] String [] parts = input.replaceAll("\\[\\[|\\]\\]","") .split("\\],\\["); // now split by comma and add it to the list for( String s : parts ){ multiDimArray.add( s.split(",") ) ; } String [][] result = multiDimArray.toArray( new String[multiDimArray.size()][]); 

那里。 现在你的result是一个二维动态创建的数组,包含: [[1], [2, 3], [4, 5, 6, 7], [8, 9, 10, 11, 12, 13]]如预期的那样。

这是一个完整的运行演示 ,它还为混音添加了更多正则表达式,以消除空白区域。

我让你处理其他场景。

所以我用代码来解决这个问题,从具有可变数量变量的多项式中提取系数。 因此,用户可能希望系数数组用于两个变量3 x^2 + 2 xy的多项式,或者它可以是具有三个变量的多项式。 理想情况下,您需要一个用户可以轻松查询的多维数组,因此可以转换为Integer [],Integer [] []等。

这基本上使用与jdmichal的答案相同的技术,使用Array.newInstance(obj.getClass(), size)方法。 对于多维数组,obj可以是一个较少维度的数组。

带有随机创建元素的示例代码

 import java.lang.reflect.Array; import java.util.Arrays; import java.util.Random; public class MultiDimArray { static Random rand = new Random(); /** * Create an multi-dimensional array * @param depth number of dimensions * @return */ static Object buildArray(int depth) { if(depth ==1) { // For 1D case just use a normal array int size = rand.nextInt(3)+1; Integer[] res = new Integer[size]; for(int i=0;i