阅读书目,华章出版社 《深入理解 Java 虚拟机》第二版 周志明著
记录读书体会,笔记内容掺杂个人理解,必定会有大量不妥甚至不对的地方,随着知识的积累会不断修正错误之处
原书 212 页
1 原书内容
运行之后发现没有输出”SuperClass init!”,说明并没有出发类org.fenxisoft.classloading.SuperClass的初始化阶段。但是这段代码里面出发了一个名为”[Lorg.fenxisoft.classloading.SuperClass”类的初始化阶段,对于用户来说,这并不是一个合法的类名称,它是一个由虚拟机自动生成的、直接继承于java.lang.Object的子类,创建动作由字节码指令newarray触发。
这个类代表了一个元素类型为org.fenxisoft.classloading.SuperClass的一位数组,数组中应用的属性和方法(用户可以直接使用的只有被修饰为public和length属性和clone()方法)都实现在这个类里。
原书代码
public class ClassInitialization {
public static void main(String[] args){
SuperClass[] sca= new SuperClass[10];
}
}
class SuperClass{
static{
System.out.println("SuperClass init!");
}
private static int value = 123;
}
2 归纳
- SuperClass[] 是一个类,由虚拟机自动生成,继承于java.lang.Object类,创建动作由字节码指令 newarray 触发。
- SuperClass[] 类存在一个 length 属性。
3 思考
- 如何查看虚拟机动态生成的 SuperClass[] 类的源码呢?没有解决掉,待后续思考
- 通过反射查看 SuperClass[] 类方法和属性
反射用例
public class ClassInitialization {
public static void main(String[] args){
SuperClass[] sca= new SuperClass[10];
show(sca);
}
public static void show(SuperClass[] sac){
System.out.println("ClassName:"+sac.getClass().getName());
System.out.println("Superclass:"+sac.getClass().getSuperclass());
Class[] interfaces=sac.getClass().getInterfaces();
System.out.print("Superinterface:");
for(Class in:interfaces){
System.out.print(in.getName()+", ");
}
System.out.println();
Field[] fields=sac.getClass().getDeclaredFields();
System.out.print("DeclaredFields:");
for(Field field:fields){
System.out.print(field.getName()+", ");
}
System.out.println();
System.out.print("Modifier:");
System.out.print(new Modifier().toString(sac.getClass().getModifiers()));
System.out.println();
System.out.print("Methods:");
showAllImpMethods(sac.getClass());
for(Method m:sac.getClass().getSuperclass().getDeclaredMethods()){
System.out.print(m.getName()+", ");
}
}
static void showAllImpMethods(Class cla){
Class[] interfaces=cla.getInterfaces();
if(interfaces.length==0) return;
for(Class c:interfaces){
showAllImpMethods(c);
if(c.getMethods().length>0){
System.out.print(c.getName()+": ");
for(Method m:c.getMethods()){
System.out.print(m.getName()+", ");
}
}
}
}
}
运行结果如下
ClassName:[Lnoname.SuperClass;
Superclass:class java.lang.Object
Superinterface:java.lang.Cloneable, java.io.Serializable,
DeclaredFields:
Modifier:abstract final
Methods:finalize, wait, wait, wait, equals, toString, hashCode, getClass, clone, registerNatives, notify, notifyAll,
4 不解
从反射结果中可以看出确实自动生成一个声明为 [Lnoname.SuperClass 类型的类,继承自 java.lang.Object,并实现 Cloneable 和 Serializable 接口,可是并不存在 length 属性!
5 搜寻答案
- 数组是特殊的对象,由虚拟机通过 newarray(创建一个原始型的数组)和 anewarray(创建一个引用型数组)指令在运行时自动创建。
public class ClassInitialization {
public static void main(String[] args) {
int[] array = new int[10];
int i = args.length;
}
}
对应的字节码内容如下
aload_0
arraylength
istore_1
return
- 数组类的 Class 对象不是由类加载器创建的,而是由 Java 运行时根据需要自动创建。数组类的类加载器与其元素类型的类加载器是相同的;如果该元素类型是基本类型,则该数组类没有类加载器。
- 数组的length即不是方法,也不是字段,在一个数组对象上调用length,会被Java编译器编译成一条 arraylength 指令,而访问字段的语句会被编译成 getfield 或 getstatic 指令。
- Java 对数组的操作是指令级的,Java 字节码中有许多单独针对数组的指令,它们在其它任何非数组类型的对象上调用都是毫无意义的。
- 所以原书中说 length 是数组类型对象的 public 属性有点不妥
- 目前我的理解是这样子的,2015/08/24,希望可以有进一步的理解。