Arrays如何在Java的ByteCode中工作

Cil*_*nco 4 java arrays bytecode

如果我使用像List,Vector或其他类似的普通类,我得到一个size()函数,它返回所考虑的类的长度,但如果我使用类的数组或默认数据类型,我得到一个公共成员长度,返回当前数组的长度.

int a[] = new int[3];
a.length; // used without ()

Vector<Integer> v = new Vector<Integer>();
v.length(); // used with ()
Run Code Online (Sandbox Code Playgroud)

这是为什么?我的意思是一个数组不是自己的类不是吗?因此,如果它不是类,它就不能有成员可变.我不知道如何在后台处理(ByteCode).我知道内存中的数组存储有指向数组第一个元素的指针,并且索引(i)内存指针被移位到ArrayPointer + i*(size of DataType).

现在您可以说计算机遍历数组的所有元素并计算所有元素,但计算机如何知道数组的结束位置以及下一个数组的起始位置?从哪里来的"成员可变"来自存储大小的数组?

我的意思是我们经常使用数组,但我知道在ByteCode中Java代码背后会发生什么.你能解释一下这是怎么回事吗?

Ant*_*ony 12

数组是Java中的对象,但它们与实际类不对应.实际上,JVM会动态地隐式创建数组类,但出于性能原因,它们不是实际的类.

由于它们是对象,因此它们可以存储在对象字段中并像往常一样传递.但是,它们在字节码级别上的处理方式略有不同.

首先,阵列与所创建的newarray,anewarraymultinewarray为分别单一维度灵长类动物的,单维对象,和多维数组的说明.相反,使用new指令创建常规对象.

使用*aload*astore说明完成获取和设置元素.

此外,x.length不是真实的字段.相反,它被编译为arraylength指令.通过编译以下代码可以看出这一点.

public void test(int size){
    int[] x = new int[size];
    String[] y = new String[size];
    System.out.println(x.length);
    System.out.println(y.length);
}
Run Code Online (Sandbox Code Playgroud)

得到以下字节码

.method public test : (I)V
    .limit stack 2
    .limit locals 4
    iload_1
    newarray int
    astore_2
    iload_1
    anewarray java/lang/String
    astore_3
    getstatic java/lang/System out Ljava/io/PrintStream;
    aload_2
    arraylength
    invokevirtual java/io/PrintStream println (I)V
    getstatic java/lang/System out Ljava/io/PrintStream;
    aload_3
    arraylength
    invokevirtual java/io/PrintStream println (I)V
    return
.end method
Run Code Online (Sandbox Code Playgroud)

尝试length通过手动创建字节码来访问该字段将导致异常,因为该字段实际上不存在.

.method static public main : ([Ljava/lang/String;)V
    .limit stack 1
    .limit locals 1
    aload_0
    getfield [Ljava/lang/String; length I
    return
.end method
Run Code Online (Sandbox Code Playgroud)

结果是

Exception in thread "main" java.lang.VerifyError: Expecting reference to class i
n class ArrayTest at constant pool index 30 in method ArrayTest.main([Ljava/lang
/String;)V
        at java.lang.Class.getDeclaredMethods0(Native Method)
        at java.lang.Class.privateGetDeclaredMethods(Unknown Source)
        at java.lang.Class.getMethod0(Unknown Source)
        at java.lang.Class.getMethod(Unknown Source)
        at sun.launcher.LauncherHelper.getMainMethod(Unknown Source)
        at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)
Run Code Online (Sandbox Code Playgroud)