java对象的内存布局

在Java程序中,我们拥有多种新建对象的方式。除了最为常见的new之外,我们还可以通过反射机制、反序列化、object.clone方法以及Unsafe.allocateInstance方法来新建对象Object.clone方法和反序列化通过直接复制已有的...

  • 在Java程序中,我们拥有多种新建对象的方式。除了最为常见的new之外,我们还可以通过反射机制、反序列化、object.clone方法以及Unsafe.allocateInstance方法来新建对象
  • Object.clone方法和反序列化通过直接复制已有的数据,来初始化新建对象的实例字段。Unsafe.allocateInstance方法则没有初始化实例字段,而new语句和反射机制,则是通过调用构造器来初始化实例字段
  • 以new语句为例,它编译而成的字节码将包含用请求内存的new指令,以及用来调用构造器的invokespecial指令
    //Foo foo = new Foo(); 编译而成的字节码
    0 new Foo
    4 invokespecial Foo()
    7 astore_1
    

      

  • 提到构造器,就不得不提到java对构造器的诸多约束。首先,如果一个类没有定义任何构造器的话,java编译器会自动添加一个无参数的构造器
    // Foo类构造器会调用其父类的Object的构造器
    public Foo();
     0 aload_0[this]
     1 invokespecial java.lang.Object() [8]
     4 return
    

      

  • 然后,子类的构造器需要调用父类的构造器。如果父类存在无参数构造器的话,该调用可以是隐式的,也就是说java编译器会自动添加对父类构造器的调用。但是,如果父类没有无参数构造器,那么子类的构造器需要显式地调用父类带参数的构造器
  • 显式调用又可以分为两种,一是直接使用“super”关键字调用父类构造器,二是使用“this”关键字调用同一个类中的其他构造器。无论是直接的显式调用,还是间接的显式调用,都需要作为构造器的第一条语句,以便优先初始化继承而来的父类字段。(不过这可以通过调用其他生成参数的方法,或者字节码注入来绕开。)

本文标题为:java对象的内存布局