深入理解 Java 虚拟机

阅读书目,华章出版社 《深入理解 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,希望可以有进一步的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值