5、从虚拟机的角度来看,一个新的对象已经产生了,但从Java查询的视角来看,对象创建才刚刚开始—— <init>方法还没执行,所有的字段都还为零。
执行完new指令之后会接着执行<init>方法,把对象按照程序员的意愿进行初始化。这样一个真正的对象才算完全产生出来。
三、对象的内存布局
对象在内存中存储的布局可以分为3块局域:对象头(Header)、实例数据(Instance Data)、对齐填充(Padding)。
实例数据:对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。
对齐填充:并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。
四、对象的访问定位
建立对象是为了使用对象,我们的Java程序需要通过栈上的reference数据来操作堆上的具体对象。目前主流的访问方式有使用句柄和直接指针两种。
1、如果使用句柄访问的话,那么Java堆中将会划出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型各自的具体地址信息。
2、如果通过直接指针访问,那么Java堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,而reference中存储的直接就是对象的地址。(Sun HotSpot的实现方式)
五、虚拟机类的加载机制
(一)、类加载的时机
1、类的生命周期:类从被加载到虚拟机内存中开始,到卸载出内存为止。
图中,加载、验证、准备、初始化和卸载这五个阶段的顺序是确定的,类的加载过程必须按照这种顺序按部就班的开始,而解析阶段则不一定。
2、需立即对类进行“初始化”(而加载、验证、准备自然需要在此之前开始)的有且只有的5种请求:
① 遇到new、gerstatic、putstatic或invokestatic这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。
如:使用new关键字实例化对象时候,读取或设置一个类的静态字段(被final修饰,已在编译期把结果放入常量池的静态字段除外)的时候,以及调用一个类的静态方法的时候。
②使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。
③当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。
④当虚拟机启动时,用户需要指定一个要执行的主类(包括main()方法的那个类),虚拟机会先初始化这个主流。
⑤当使用JDK1.7的动态语言支持时。
(二)、类加载的过程
类加载的全过程:加载、验证、准备、解析和初始化这五个阶段。
1、加载
“加载”是“类加载”过程的一个阶段。
① 通过一个类的全限定名来获取定义此类的二进制字节流(通过类加载实现);
② 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;
③ 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
2、验证
连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
大致完成4个阶段的检验动作:文件格式验证、元数据验证、字节码验证、符号引用验证。
3、准备