数组对象的类是什么?
既然数组是对象,那么数组究竟是什么呢?当然,不是java.util.Arrays。
public class TestArray {
private class Dog {
}
public static void main(String[] args) {
int a[] = new int[10];
int b[] = new int[5];
//Dog a[][] = new Dog[2][];//[[LTestArray$Dog;
//int a[][][] = new int[2][][];//[[[I
//long a[][] = new long[10][];//[[J
//float a[] = new float[2];//[F
//String a[][] = new String[10][];
//[[Ljava.lang.String;
Class clazz = a.getClass();
System.out.println(clazz.getName());
Class clazzb = b.getClass();
System.out.println(clazzb.getName());
}
}
根据上面的实例,可以得出结论:
ü 数组的类名由若干个’[‘和数组元素类型的内部名称组成,’[‘的数目代表了数组的
维数;
ü 具有相同类型元素和相同维度的数组,属于同一个类,如果两个数组的元素类型相
同,但维度不同那么它们也不属于同一个类,如果一个数组的元素类型和维度相同,但长度不同,那么他们还是属于同一个类;
(2) 数组的类有哪些成员?
实例测试:
public class TestArray {
private class Dog {
}
public static void main(String[] args) {
int a[] = new int[10];
Class clazz = a.getClass();
System.out.println(clazz.getName());
System.out.println(clazz.getDeclaredFields().length);
System.out.println(clazz.getDeclaredMethods().length);
System.out.println(clazz.getDeclaredConstructors().length);
System.out.println(clazz.getDeclaredAnnotations().length);
System.out.println(clazz.getDeclaredClasses().length);
System.out.println(clazz.getSuperclass());
}
}
打印结果:
[I
0
0
0
0
0
class java.lang.Object
可见,[I这个类是java.lang.Object的直接子类,自身没有声明任何成员变量、成员方法、构造函数和Annocation,可以说:[I就是一个空类。学到这里,我们起码会产生这样一个疑问:为什么连length这个成员变量都没有呢?因为我们经常使用数组.length来获得数组的长度,编译器怎么就没有报错了?
数组的类在哪里声明?
类加载器先看看数组类是否已经被创建了。如果没有,那就说明需要创建数组类;如果有,那就无需创建了。
如果数组元素是引用类型,那么类加载器首先去加载数组元素的类。
JVM根据元素类型和维度,创建相应的数组类。
可见,是JVM自己在运行时生成了数组的类对象;再细想,JVM必须动态生成数组类,因为JAVA数组类的数量和元素类型、维度(最多255)有关,可见是无法预先声明好的。
没有length这个成员变量!
我们已经发现, JVM没有为数组类生成length这个成员变量,那么Array.length这样的语法如何通过编译,如何执行的呢?
让我们看看字节码吧!编写一段最简单的代码,使用jclasslib查看字节码。
1.public class Main {
2. public static void main(String[] args) {
3. int a[] = new int[2];
4. int i = a.length;
5. }
6.}
使用SUN JDK 1.6编译上述代码,并使用jclasslib打开Main.class文件,得到main方法的字节码:
0 iconst_2 //将int型常量2压入操作数栈
1 newarray 10 (int) //将2弹出操作数栈,作为长度,创建一个元素类型为int, 维度为1的数组,并将数组的引用压入操作数栈
3 astore_1 //将数组的引用从操作数栈中弹出,保存在索引为1的局部变量 (即a)中
4 aload_1 //将索引为1的局部变量(即a)压入操作数栈
5 arraylength //从操作数栈弹出数组引用(即a),并获取其长度(JVM负责实现如何
//获取),并将长度压入操作数栈
6 istore_2 //将数组长度从操作数栈弹出,保存在索引为2的局部变量(即i)中
7 return //main方法返回
可见,在这段字节码中,根本就没有看见length这个成员变量,获取数组长度是由一条特定的指令arraylength实现(怎么实现就不管了,JVM总有办法)。编译器对Array.length这样的语法做了特殊处理,直接编译成了arraylength指令。另外,JVM创建数组类,应该就是由newarray这条指令触发的了。