呃,昨天吃完饭血液大多涌向了胃部,然后我的脑子闹脾气了:明明晚上还要我干活,结果不给我充足的血液怎么行呢?所以它罢工了,那我也没有办法,只能今天再写这一篇了哈哈哈。
很巧妙的掩饰了自己昨天的懒惰之后,我们话不多说,继续继续。
昨天说到classloader将字节码文件加载到jvm的时候有三个阶段,分别是装载、连接和初始化三个过程。下面我就来分别聊聊这三个阶段(昨天抄的博客和今天抄的内容居然冲突了,可恶,我还得再去看看哪个是对的)
1.装载
装载的主要过程是先将.class的信息读取到内存中来,首先通过类的全限定名读取到描述此类的二进制流,这个全限定名我的理解是包名加类名,大致是这种形式的:com.mysql.jdbc.Driver,然后这个字节流所代表的静态存储结构转化为方法区的运行时结构,然后在堆中生成一个这个类的java.lang.Class对象,作为方法区数据的访问入口,这个对象呢,不是String s=new String();这种对象,s是一个对象,但它是String类的,而我们刚才生成的对象是 Class c=s.getClass();这种,这个对象的类是class,而且对于每一个类来说,它在堆中的class对象都只有一个。
2.连接
连接分为三个部分,分别是验证,准备和解析
昨天好像说到,运行一个类之前我们起码得先看看这东西是不是坏的吧,要不然给我机子跑坏了那可就不好了,所以呢,当装载完毕之后,第一时间就要检查字节信息是否符合jvm的规范,这些规范包括文件格式、元数据、字节码和符号引用的验证。(你看懂上面的规范了吗?我反正没看懂,全是抄的哈哈哈。)
接下来是准备阶段,准备阶段是正式为类变量分配内存并为类变量设定初始值的阶段,静态变量赋予默认值(int a=0,object o=null,你赋予的值不算),常量赋予初始值(就是你给这个常量赋予的值)
然后是解析阶段,我们刚才用的是全限定名来引用一个类,比如:com.mysql.jdbc.Driver,但是现在我们已经将这个类的class对象创建出来了,所以直接用堆中这个类的实际地址就可以了。
3.初始化
初始化阶段主要干的是初始化静态块的内容,并对静态变量进行真正的赋值操作,这里jvm会执行编译器自动生成的()方法,这个()干了些啥呢,简单来说就是搜集了类中static{}静态块组成的代码(没有构造器的代码!!!前面有篇博客坑我),然后挨个执行下去就行了。这个阶段我有点疑惑啊,既然你说执行的是静态代码块的东西,那public static a=10;这个你是执行还是不执行呢?这个算静态代码块吗?后来上网上再查了一下,这语句也运行,那这个初始化基本上所有的静态变量就都拥有了自己的初始值了。这里还有再强调一点,如果这个类还有父类,那么首先要先把它的父类也给加载进来,流程一样
装载完之后终于到了执行代码的阶段了,运行个程序可真累,如果需要一个对象,那么我们需要调用它的构造函数,也就是init方法,生产出一个对象放入堆中。
累了累了,不写了,剩下的晚上再写,我发誓晚上必写!!!