Java的多维数组

阅读更多
继续打捞站内信。

同学F 写道
在java中的数组访问,举个例子,对于数组int[][][] arry = new int[2][3][4],我从字节码上看,虚拟机对某个arry中的某个元素如arry[1][1][3]的访问,似乎是先获取arry[1]的引用,然后再获取arry[1][1]的引用,再获取数据arry[1][1][3],如果这个过程我没有理解错的话,那么虚拟机是不是对这些“中间引用”(arry[1]、arry[1][1]之类的)创建相应的类型,否则单凭这些引用如何进行数组下表的越界校验?


Java和JVM里本来就没有所谓的“矩形数组”的概念,多维数组只有“数组的数组”(array-of-arrays)或者叫jagged array。
与之对比,C#和CLI里就有真正的多维“矩形”数组,也支持“数组的数组”。关于几种不同的语言里多维数组的差异,可以参考 以前一帖。

也就是说,在Java里
类型 说明
int 这是一个基本类型
int[] 这是以int为元素的数组类型
int[][] 这是以int[]为元素的数组类型
int[][][] 这是以int[][]为元素的数组类型

一个数组类型的“组件类型”( component type)就是该数组类型的维度(dimension)减去1的类型;字面上看也就是少一对[]。

每个维度上都是一个真正的数组对象。每个数组对象都记录着自己的长度(length)。所以对每个数组对象都可以用arraylength指令去查询它们的长度,每个Xaload / Xastore也就可以做相应的边界检查。

int[][][] array = new int[2][3][4];

这只是个简写而已。虽然这个语句的右手边对应与一组JVM字节码指令,
   0:	iconst_2
   1:	iconst_3
   2:	iconst_4
   3:	multianewarray	#2,  3; //class "[[[I"

实际上它的作用 大致等同于:
int[][][] a = new int[2][][];
for (int i = 0; i < a.length; i++) {
  a[i] = new int[3][];
  for (int j = 0; j < a[i].length; j++) {
    a[i][j] = new int[4];
  }
}


以32位HotSpot VM的实现为例,上面两个版本的代码创建出来的对象都是这种样子的:
Java的多维数组_第1张图片


这样就好理解了吧?

可以参考JVM规范去了解multianewarray的语义:
http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2.doc9.html#multianewarray

HotSpot VM的实现里,参考解释器版的实现比较直观,在这里:
interpreterRuntime.cpp: InterpreterRuntime::multianewarray
objArrayKlass.cpp: objArrayKlass::multi_allocate
typeArrayKlass.cpp: typeArrayKlass::multi_allocate

该指令接受两个参数,
第一个是多维数组的类型,这个例子是里[[[I,也就是int[][][];
第二个是多维数组的维度n,这个例子里n=3。
知道了维度之后,JVM执行这条指令时就会从操作数栈顶弹出n个值(必须都是int型),并以这些int为每个维度的length嵌套循环的去创建数组对象出来;这个例子里也就是把前面iconst_2、iconst_3、iconst_4指令压到操作数栈上的常量2、3、4分别弹出来,并且作为数组的各维度的长度去创建实例。

multianewarray与上面写的那种显式用嵌套循环来初始化多维数组的Java代码最大的差异是,multianewarray会检查所有维度上的length是否非负,如果有负数就会抛 NegativeArraySizeException;要注意的是 无论传入的多维数组是否有维度的长度是0,所有维度都会被检查
而显然,如果显式用嵌套循环来初始化的话,负数长度的问题就有可能“逃过去”。

看例子:
public class Foo {
  public static void main(String[] args) {
    int[][][] array = new int[1][0][-1];
  }
}

这个会抛NegativeArraySizeException异常:
$ java Foo
Exception in thread "main" java.lang.NegativeArraySizeException
        at Foo.main(Foo.java:3)



public class Bar {
  public static void main(String[] args) {
    int[][][] a = new int[1][][];
    for (int i = 0; i < a.length; i++) {
      a[i] = new int[0][];
      for (int j = 0; j < a[i].length; j++) { // a[i].length == 0
        a[i][j] = new int[-1];                // 这个循环体不会被执行,-1的长度就被“跳过去”了
      }
    }
  }
}

这个不会抛异常。
  • Java的多维数组_第2张图片
  • 大小: 179.1 KB
  • 查看图片附件

你可能感兴趣的:(Java,JVM,Oracle,ITeye,J#)