如果我使用像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代码背后会发生什么。你能告诉我这是怎么可能的吗?
答案 0 :(得分:12)
数组是Java中的对象,但它们与实际类不对应。实际上,JVM会动态地隐式创建数组类,但出于性能原因,它们不是实际的类。
由于它们是对象,因此它们可以存储在Object字段中并像往常一样传递。但是,它们在字节码级别上的处理方式略有不同。
首先,分别使用newarray
,anewarray
或multinewarray
指令创建数组,分别用于单维原始,单维对象和多维数组。相比之下,使用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)
数组类型实际上是类!存储在内存中时,它们包含它们的基本类信息(包括它们包含元素的类信息,如果它们不是本机数组),它们保存的元素数量,以及实际的数组数据。数组对象中的length
是final
字段而不是方法,因为数组永远不会包含不同数量的元素。
对于其他类型的结构,例如Vector
,对象中的元素数量可能会随时变化,因此length()
必须是一种方法。与String
类似:即使String
类是不可变的,它也会从length()
继承CharSequence
方法;某些CharSequence
的长度可以变化,因此它再次作为方法实现。