不同于C++,Java是一种动态加载机制。在程序刚开始执行时,程序中的对象并没有加载进JVM;只有当我们第一次需要某个类或者对象的时候,Java才会动态的加载类文件(xxx.class)并创建相应的对象到内存中。那么这个创建的过程是什么样的呢?下面就用我个人的理解详细描述下:
通过一个编写好的类来创建对象,JVM需要借助一个叫类装载器(class loader)的子系统来实现。所有类的装载都是在第一次使用类时,即当程序中第一次引用类中的静态成员时动态完成的。由于构造方法也是一个静态方法(虽然构造方法中没有static关键字,但它的确是静态方法),那么通过new关键字来创建一个新对象也可以被认为是引用类中的静态成员。具体实现步骤如下:
- 当需要加载一个类时,类加载器会首先检查所需要的类(比如Person)是否已经加载进内存。如果没有,类加载器会根据路径去查找与类名相同的类文件(比如,Person.class)文件来加载。类文件会被加载到内存中的静态区(也叫方法区),静态区中的内容从程序开始到结束的整个区间会一直存在。当类加载入内存以后,JVM会自动检查类是否完整以及类中是否包含坏代码,从而确保载入的类数据没有错误。(这里为何叫类数据,而不叫类文件呢?因为类一旦进入内存,就转化成二进制数据了,原来的文件不会存在于内存中)
- 当类加载入内存后,加上就会开始静态初始化的过程:在静态区中为类创建静态变量并赋值(若程序中没有初始值,则根据数据类型置为默认值),执行类的构造方法以及其他静态方法。
- 执行构造方法也就是创建对象的过程。Java会首先在堆和栈中分配足够的空间来装载类的对象,空间的结构以及各个指定段的名称,也就是成员变量的内存地址,会根据类的描述来指定,引用类型的成员变量存放的堆中,基础类型的成员变量存放在栈中。如果构造方法中有给成员变量赋值的语句,那么成员变量就会被相应的赋值。同时,如果类中还有其他静态方法,那么这些方法也都会执行。
- 静态初始化完成后,Java会有个默认设置:即给所有未赋值的成员变量赋默认值。经常写程序的人都知道,忘记给成员变量赋值,是很多程序BUG的源头。因此Java引入了这样的机制,默认给所有未赋值的成员变量赋予初始值。
- 至此,对象就创建完成了。对象中的静态成员,方法都存放在静态区中,基础类型的成员变量都存放在栈中,引用类型的成员变量都存放在堆中。
更正:上面步骤有错误的地方,一个类初始化的顺序是:开辟空间,所有成员变量设置为默认值。然后,如果类中有变量赋值语句,则执行顺序如下,不论程序中语句的先后顺序:
- 执行静态变量赋值语句,给静态成员变量赋值。
- 执行非静态成员变量赋值语句,给非静态成员变量赋值
- 调用构造方法中赋值语句,给成员变量赋值