00:00
接着呢,咱们来看第二个阶段,在有了第一个叫做加载阶段以后,第二阶段呢,我们称为叫链接啊linking,呃,这个linking阶段呢,我们又分成三个具体的子阶段啊,第一个呢叫做验证verify,第二个呢是准备啊prepare,呃,第三个呢叫解析啊resolve,那么验证我们一个一个来看一下哈,首先呢,我们在经过这个loading阶段以后,已经呢能够在这个内存当中生成大的class的一个实例了啊,那么验证阶段做什么呢?主要呢,是在于确保大了class文件中的这个自节流中诶包含的这个信息啊,是符合诶当前虚拟机的要求的啊,保证呢被加载类的正确性,不危害虚拟机自身的安全啊,这里边提到了有具体的四种格式的验证啊,具体细节展开呢,咱们就不用多说了啊,那举个例子呢,那我们在一开始提到。这个类类加载器的时候呢,说class文件呢,都是以特定的文件标识开始的,那不妨呢,咱们就看一下啊,比如说咱们找到自解码文件。
01:02
打开。那正好咱们这里边也有很多的这个自节码文件了啊,比如说先以咱们这个第一章中讲到的这样一个自己码文件为例啊,CTRLC大家呢,可以把它放在桌面上啊,方便起见我就放在这儿了,然后我们再找一个,比如说这个第二张。第二张呢,咱们刚才用到了一个是hello loader,嗯,CTRLC,诶我就以这样的两个为例,这两个呢,呃,最起码文件放到桌面上以后呢,大家如果双击打开,或者是你有一个默认的打开方式呢,通常都是一个记事本啊,你要用记事本打开的话呢,那就不是特别靠谱了啊,打开以后呢,就会出现这样情况,诶这是不对的,那我们这时候呢,就需要一个专门能够去解读咱们自建码文件的一个工具啊,那这个工具的话呢,就是我这里边已经安装好的这个工具。哎,这个接class lab啊,这个我们确认一下。啊,这就可以了啊,那现在呢,我们其实用它打开的话呢,其实是类似于一个反编译了,其实是啊是这样的一个过程,但现在我们其实还不太想看这样一个过程,诶我这呢是用它来打开的,其实还需要装另外一个软件哈,就是这两个工具呢,我们在后边讲资金软文件的时候呢,会具体来展开说在装一个,诶这个啊叫班主任这VIVO就是二进制啊,自己码的一个查看器。
02:26
哎,我先把它打开演示一下啊嗯,打开以后呢,大家只需要呢,把这个文件呢拖进来就可以了。好了,拖进来以后呢,大家会看到我们这个资金码文件,它的起始的这个内容叫做咖啡baby啊,咖啡宝贝这儿呢,诶我们称为叫魔术,那所有的这个能够被扎va逊尼所识别的自己码文件,它的一个有效的起始都是叫fe baby,那你可能会有其他语言的这个自己码文件,然后被非Java虚拟机呢去解释运行,那人家就不是cafe baby了啊,那这呢就是专属给Java识别Java群拟机啊这样的一个标识,这呢是咱们开的,嗯,这个刚才第一个文件是吧,我们再来看一下这个第二个文件,大家会看到第二文件呢,也是以cafe baby开头的,这就是我们所谓的这个校验的一个过程啊,那刚才呢,提到的这两个工具呢,大家可以在我们的资料有个软件啊啊,这是一个刚才用的我们是这个啊,还有这个j class lab啊,大家可以去安装一下,呃,这就不多说了啊,然后呢,再回过来。
03:32
那刚才提到了说这个特定的一个标识,提到了一个校验的过程,那这个校验的话呢,就是在我们这个验证阶段来实现的,那如果发现呢,你不是一个合法的这个资金码文件的话呢,它会报叫very帅的一个error,那怎么会出现不合法呢?因为我们知道这个资金码文件呢,它呃也算是这个二进制了,完全用户可以去手动的,比如说你从键盘上敲零跟一啊这样的硬拼出来一个所谓的自建码文件,那肯定它是一个不合法的,甚至说呢,还有可能针对一次解码文件拦截以后呢,进行一些恶意的修改攻击啊,导致呢程序运行呢崩溃,那为了防止出现崩溃的情况,我们先得有一个验证的过程啊,这就是在这个环节出现的啊,然后第二个环节呢,我们称为叫prepare,准备位列变量呢,分配内存,然后并且呢,设置该变量的一个默认初始值及零值,哎,这个呢,是需要做一个注意啊,那咱们还是举一个例子回过来。
04:33
嗯,那我们开开这个程序吧。哎,这个程序里边呢,有一些信息我们暂时先给它删掉啊,这用不着先关掉干掉啊,行看这那我们在这个类当中声明了一个static的一个变量啊,我们称为叫类变量或者叫静态变量,那此时呢,我给这个静态变量显示赋值了一个叫一这样一个数值,那我们现在想要强调的就是在这个prepare这样一个环节呢,我们此时的这个变量A,诶只是会赋值为零。
05:05
哎,只是会复制为零,也就是说呢,在prepare诶这样的一个环节呢,我们这个A呢,A呢是被复制为零,然后在它的下一个环节当中,下一个环节呢,就是我们所谓的呃,叫初始化啊。诶initial哎,我这样写一下啊,在这个环节当中,我们这个A呢,才被诶复制为是一个一,诶是这样的一个过程,那我们现在先只关注于这样一个事情,那数据的类型不一样,它的初始值呢也会不同,这个呢应该不用多说了,大家应该都清楚啊,像数值类型的话呢,整形呢都是零,呃负电型呢都是0.0,这个叉类型呢,就是杠U0000是吧,波尔类型呢就是一个false,那引用类型呢,都是no啊这个咱们再做一个温习啊,在准备环节呢,都是负的,所谓的默认初始值,注意这里边想要强调一点就是我们如果一个static的变量被final修饰的,那注意它就不是变量了啊,而是变化为一个常量啊,我们上边的说的呢,其实都是变量啊,那如果它是个常量的话呢,我们在编译的时候呢,其实就已经给它分配值导。
06:16
啊,就会已经分配值了哈。呃,准备阶段的话会显示的初始化,那在这个时候呢,做一个显示初始化,就给大家确定好最这个直接的这个数值,比如说你final的声命成它是数值是五,那这个时候呢,就赋值为五了,因为后期呢,不会对它再进行修改了啊,是这样,那这里面再强调一点,就是在准备阶段呢,不会为实例变量呢分配初始化啊,因为这时候我们还没有去创建对象的啊,还是类的一个加载过程,后续呢我们去执行,嗯,具体的这个比如方法里边我们去造一个对象,才会涉及到实际实例变量的一个具体的初始化了,行,然后第三个环节呢,叫做解析啊,这个解析呢,大家了解一下就行啊,因为通常我们说这个解析呢,都是放在这个初始化之后来完成的啊,将常量池当中的符号引用转化为对应的这个直接引用啊,所以的这个号引用呢,呃,我们之前还是回到这个子金码文件哈,呃,像常量池里边我们对应的这都是一些标号了啊,然后把它转化成对应的一些直接引用。
07:19
啊,嗯,这个我们再打开,说这个符号引用呢,就是一组符号来描述所引用的一个目标啊,因为咱不可能,嗯,比如说咱刚才写的这个程序,看似这个程序呢,其实代码量很小啊,但是我们这个类在执行的过程当中,其实会加载非常多的类啊,那整个加载你不可能把所有的类呢,都在我们对应的这个字节码文件当中啊,全部装在这里边,这不太现实,这个文件呢,其实它本身呃比较小是吧?呃,那这时候我们就需要使用这个符号引用去引用你相关的一些结构啊举个例子,比如说我们在这呢,你看写了一个c out对吧,输出语句哈,那咱们把它呢,呃,是这个文件啊,把它进行一个。这个反编译。
08:01
举个例子。嗯,咱们现在是在这个第二章啊。哎,行,CD。行,然后我们对咱们刚才这个程序进行一个反编译啊P。诶出来了,出来以后的话,你会发现我们在上面的过程当中,你看这是我们的这个常量池的一个信息啊,我们会加载很多的结构哈,你当前自己这个类,还有object类,还有系统类,还有打印流这个类,对吧,这些结构呢,都需要我们去做一些加载,因为你像你这用到了这个输出语句嘛,那这呢,我们都会有对应的一些符号引用,然后在我们的这个解析环节呢,会把它转化成对应的一些,呃,叫直接引用。啊,转换成直接引用,直接引用呢,就是直接指向你目标的一个指针相对偏移量,或者一个间接的定位的句柄,啊,那解析动作呢,呃,主要针对于类接口字段,然后呢,这个类方法。
09:11
这个接口方法方法类型等来实现的啊,那这块呢,具体的内容咱们就先不过多的来说了,呃,等咱们讲到这个内存和垃圾回收的下一篇专门讲这个自节码文件的时候啊,咱们再来具体的来讲解啊,这样的一个过程啊,那暂时呢,我们这块呢,先不作为一个中心来说明,好这呢就是我们说类加载的这个第二环节叫做linking啊,链接阶段的三个环节,大家清楚一下每个环节的主要操作就可以了。
我来说两句