本人小白一枚,看java类的初始化的时候好晕的说,我觉着书上虽然说的对,但总觉得有些信息没说出来,没说清楚,看了好多文章博客的,现在有些感悟,来小写下总结,也算是为以后再次复习种个好果子。
先摘一下书上写的:
加载:将类的class文件读入内存,并为之创建一个java.lang.class对象。
连接:把类的二进制数据合并到JRE中,检查被加载的类是否有正确的内部结构,并和其他类协调一致。为类的静态FIELD分配内存,设置默认值,将类的二进制数据中的符号引用替换成直接引用。
初始化:主要对静态Field进行初始化,初始化方式两种:声明静态Field时指定的值,使用静态初始化块为其指定初始值。JVM会按他们的顺序执行。初始化包括以下步骤:
假设该类没有被加载和连接,则先加载并连接该类。
假设他的父类没有被初始化,则先初始化他的父类
假设类中有初始化语句,则系统依次执行。
看完之后我脑子里一直就盘旋着几个问题:
1、类的加载和初始化神马的和构造函数有啥关系和区别?
2、类的初始化会为实例属性分配内存吗?
3、如果我要创建一个实例对象,到底是怎么个创建流程?
OK,如果你也有以上的疑问,那么我们一起来看看到底是怎么回事!我会直接回答最后一个问题,当你把这个问题弄明白了,前面的就迎刃而解了。
public class Person{
static{staticInt = 6; }
{vInt =15; }
static int staticInt = 3;
int vInt = 10;
Person(){
staticInt = 9;
vInt = 20;
}
}
Person p = new Person();
JVM会看:
1)哎,有个变量p,然后就给它分配一个空间(这里的空间指的是指针,而不是实际的对象)
2)分完了以后发现它需要Person这个类来进行实例化,然后就到内存里找,看这个类有没有被加载到内存里来,如果有救直接用了,如果没有就会进行加载。我们就来说没有的情况
3)加载的时候,将类的class文件读入内存,并为之创建一个java.lang.class对象。这里需要重点说一下,在创建这个对象的时候,就会保存这个类的所有信息,比如这个类有哪些属性(静态的非静态的都包括),有哪些方法(静态的非静态的都包括),有什么代码块,都会被记录。
4)把类的二进制数据合并到JRE中,检查被加载的类是否有正确的内部结构,并和其他类协调一致。JVM跑到java.lang.class对象里看看,都有啥静态变量,为他们分配内存,设置默认值,将类的二进制数据中的符号引用替换成直接引用。
5)然后对静态Field进行初始化,初始化方式两种:声明静态Field时指定的值,使用静态初始化块为其指定初始值。JVM会按他们的顺序执行。这个地方需要注意:如上代码,静态的变量staticInt最后会被赋值为3,因为静态代码块在声明之前。JVM是先跑到java.lang.class对象看有什么静态变量,给他分个空间,然后再执行的声明和静态代码块语句,因此初始化之后值为3.
好了,345都是类的加载和初始化,我们再来看看都做了些什么:生成java.lang.class对象,有该类里的属性方法代码块的所有信息。再为静态属性分配了内存并执行了静态代码块,按
顺序把静态属性给初始化了。这里并没有为非静态属性分配内存,也没有执行构造函数和非静态代码块,一句话
总结就是:记录下这个类的所有属性和方法代码块等信息,为静态的变量分内存并赋值。
初始化之后,现在JVM改根据这个初始化好的类信息来进行实例化了。先前被初始化好的静态变量会被所有实例共享,静态代码块将不会再被执行,相当于失效了。我们来看看JVM接下来要干嘛?
6)JVM跑到java.lang.class对象里看一看,有哪些实例变量需要分配内存的,跟静态变量类似的,JVM先给实例变量分内存,分完之后,执行代码块和声明,在这里vInt为10。
7)最后执行构造函数,执行完后,vInt变成了20,staticInt变成了9,然后改构造函数隐性的返回一个Person实例对象给变量p。
好了,讲完了,我们再看看12问题
1、类的加载和初始化神马的和构造函数有啥关系和区别?
只要在类需要实例化的时候才会执行构造函数。而类的加载和初始化却在这些情况都会被执行:创建实例 调用静态方法 访问某个静态Field(如果该变量还是final的,则在编译阶段就能确定下来,就不会初始化) 初始化某个类子类
2、类的初始化会为实例属性分配内存吗?
不会为实例属性分配,只有在实例化的时候才会分内存
总结
1)将类的class文件读入内存,并为之创建一个java.lang.class对象。
2)把类的二进制数据合并到JRE中,检查被加载的类是否有正确的内部结构,并和其他类协调一致,并为静态变量分内存
3)为静态变量初始化赋值
以上为初始化顺序
4)为非静态变量分内存,并赋值
5)构造函数,返回构造好的对象
如果有子类父类关系的时候:
父类和子类的class文件都加载到内存,当父类,和子类有Static时,先初始化Static,再初始化子类的Static,
再初始化父类的其他成员变量->父类构造方法->子类其他成员变量->子类的构造方法。
有不对的地方还望高手指出啊
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/strong815/article/details/47041297