上一篇咱们知道了一个类的生命周期是:加载->验证->准备->解析->初始化->使用->卸载。
当初始化完成之后,一个类全部的类变量(被static修饰的变量)都被赋值。可是未被static修饰的成员变量又是什么时候被赋值的呢?函数
一个类什么时候被初始化能够分为如下几类:学习
1.建立类的实例(new)。 2.访问某个类或接口的静态变量,或者对该静态变量赋值。 3.调用类的静态方法。 4.经过反射方式执行以上三种行为。 5.初始化子类的时候,会触发父类的初始化。 6.Java虚拟机启动时被标明为启动类的类。(有main方法的类) 7.JDK 1.7开始提供的动态语言支持。(了解便可)
咱们来讲道说道第3点和第6点code
咱们日常在使用main方法和调用某个类的静态方法的时候,是否是发现,并不能直接调用静态方法和main方法所在类的非静态方法和非静态变量。对象
但是明明不是说了在调用静态方法和执行main方法的时候,所在的类已经被初始化了吗?接口
是的!在上一章节咱们就说,类初始化的时候会按照咱们编写代码的顺序为类变量(static修饰的变量)进行赋值。注意哦,此时这个类仅仅只有静态变量被正确赋值了哦。生命周期
public class People{ private static String name ="lisi"; private int age = 18; static{ name ="zhangsan"; } }
如上述代码,在该类被初始化以后,首先按照代码顺序将类变量(被static修饰的变量)赋值。因此name被赋值"lishi",而后再将name赋值为 "zhangsan"。此时age并无值,直接直接调用会报错。内存
上一个章节中,咱们明白了加载->验证->准备->解析->初始化的具体细节。虚拟机
当初始化完成后,一个类的静态变量被正确赋值。若是这个对象是被new出来的。那么在初始化完成以后会进入实例化阶段。class
实例化的具体步骤为:变量
父类非静态成员初始化语句(包括代码块,按照在类定义中的顺序执行)->父类构造函数->子类非静态成员初始化语句(包括代码块,按照在类定义中的顺序执行)->子类构造方法()
注意哦! 若是这个类有父类不光是先实例化父类。总体流程以下: 1. 加载父类 1.1 为静态属性分配存储空间并赋初始值 1.2 执行静态初始化块和静态初始化语句(从上至下) 2. 加载子类 2.1 为静态属性分配存储空间 2.2 执行静态初始化块和静态初始化语句(从上至下) 3. 加载父类构造器 3.1 为实例属性分配存数空间并赋初始值 3.2 执行实例初始化块和实例初始化语句 3.3 执行构造器内容 4. 加载子类构造器 4.1 为实例属性分配存数空间并赋初始值 4.2 执行实例初始化块和实例初始化语句 4.3 执行构造器内容
到这里,咱们就很是的清楚为何在静态方法中不能直接调用非静态的变量,由于此时的非静态变量并无被赋值。
之前我在学习的时候,new一个对象出来你们老是在说,咱们初始化了这个对象,而后balabala。。。
致使我对于初始化和实例化里的静态变量和非静态变量什么时候被赋值一直有点模糊。new一个对象出来准确的来讲是进行了初始化和实例化两个步骤,这样应该就会清晰了不少。
初始化完成之后,类被存放在方法区,注意哦,此时并无存放在堆内存中。
只有当对象实例化进入堆内存中之后才会对非静态变量进行初始化赋值。
这下总算吧一个类的初始化和实例化的细节搞明白了,关于文中的方法区,堆内存等内容,下一节再具体分析。