Arrays如何在Java的ByteCode中工作

时间:2013-12-17 22:27:56

标签: 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 ()

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

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

我的意思是我们经常使用数组,但我知道在ByteCode中Java代码背后会发生什么。你能告诉我这是怎么可能的吗?

5 个答案:

答案 0 :(得分:12)

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

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

首先,分别使用newarrayanewarraymultinewarray指令创建数组,分别用于单维原始,单维对象和多维数组。相比之下,使用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);
}

产生以下字节码

.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

尝试通过手动创建字节码来访问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

结果

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)

答案 1 :(得分:1)

java中的数组有一个类,因此是对象。构建它与“普通”类不同。更多内容可能在

Why isn't there a java.lang.Array class? If a java array is an Object, shouldn't it extend Object?

答案 2 :(得分:0)

数组实际上是一个类,它像任何其他类一样扩展Object,但它在内部由语言处理,以获得更好的性能和便利。作为一个类,它可以有字段和方法。

答案 3 :(得分:0)

数组是一个对象,您可以通过简单地将数组赋值给对象值来自己尝试。 例如:

public Object test(){
  int[] test = new int[5];
  Object obj = test; 
  return obj;
}

如果你想知道数组在字节级别是什么:数组本身只是指向一些关于数组长度的信息,一些其他信息和一个指向你预留内存的指针可以存储数据(顺序存储器大小的数组)。访问数据是一个简单的问题,查找[指针] + [indexnumber] * [sizeofeachitem],然后你知道要查看哪一块内存。

答案 4 :(得分:-1)

数组类型实际上是类!存储在内存中时,它们包含它们的基本类信息(包括它们包含元素的类信息,如果它们不是本机数组),它们保存的元素数量,以及实际的数组数据。数组对象中的lengthfinal字段而不是方法,因为数组永远不会包含不同数量的元素。

对于其他类型的结构,例如Vector,对象中的元素数量可能会随时变化,因此length()必须是一种方法。与String类似:即使String类是不可变的,它也会从length()继承CharSequence方法;某些CharSequence的长度可以变化,因此它再次作为方法实现。