00:00
那讲完局部变量表和操作数站以后呢,咱们来看一下这个叫动态链接,那看动态链接之前呢,咱们先来看一下咱们一开始讲的战争里边这个几部分的这个结构啊,哎,咱们来看这个图。战争里边呢,我们说可以分成这样的五个结构,局,无变量表,操作数站,这咱们已经讲过的,哎,然后呢,呃,动态链接,方法返回地址以及呢一些附加信息,剩下的还有这三块,那这三块呢,我们就先来讲动态链接,然后呢看方法返回地址以及呢一些附加信息,这块呢,我们想多说一句,就是这个方法返回地址,动态链接和一些附加信息呢,在有一些地方呢,把它称作叫做真数据区。会有这样的一个叫法。嗯,它呢,主要就指的咱们刚才说的像这个附加信息,这是其中的一个。这个呢,给他这样一下啊,诶这个一些附加信息,它是一种。那以及呢,就是。
01:01
哎,动态链接。这个诶方法返回地址,哎,就这三个呢,我们都统称为叫真数据区,这个在有些书上呢,会这样去叫,这个大家能清楚这样一个概念就可以了。那这是我们说的这个问题啊。就把这个指针稍微调一下好,然后回过来,哎,我们来看一下这里边这个叫诶动态链接,看这里边我们想说明什么问题啊,就是咱们说大部分这个字解码指令啊,他们在这个执行的时候呢,其实都需要呢,进行常量池的访问。啊,这一说大家有点懵啊,哎,你先注意听我这话,就是大部分的这个自建码指令他们呢,在执行的时候呢,或者就直接就说自建码指令它都需要进行常量池的一个访问,那么在咱们刚才提到这个帧数据区当中,咱们呢,就保存着能够访问诶常量池的一个指针,方便呢程序访问常量池,那么这呢,就是我们要讲的这个叫哎动态链接,那怎么讲看一下啊,说每一个战帧内部啊,都包含一个指向运行时常量池当中该战争所属方法的引用。
02:11
就是我们说啊,这个战争就是咱们对应的一个方法,这个战争里边现在存在一个叫动态链接。哎,咱们先叫动态链接啊,这边也比较短啊,这个动态链接它要干什么呢?就是指明说我到底我我是谁啊,诶你呢,就是一个方法,那个方法放哪呢?我们是在运行时常量池当中保存这个方法的一个引用啊,那咱们这个战帧呢,像呃战帧里边这个动态链接呢,就相当于保存了一下,我指向这个运营师常练池中这个方法这个引用的一个地址。啊,说的有点绕是吧,一会儿咱们一看图就知道了啊,那么包含这个引用的目的呢,就是为了支持当前方法的代码,能够实现动态链接,哎,在我们需要呢动态链接的时候呢,去使用这个动态链接呢,对应另外一个,另外一个呢,叫做静态解析,这个咱们后边呢给大家讲一讲啊静态解析。
03:01
好,那这呢是我们说的这个事情,那下边呢,说Java源文件被编译到自节码指定文件当中的时候呢,所有的变量和方法引用呢,都会作为符号引用。作为符号引用保存在class文件的常量池里,这个一说大家可能有点懵哈,来,咱们演示一下,在这个Java一下呢,新建一个class文件,不妨呢,咱们就叫叫做dynamic linking。你看它的一个test啊呃,动态链接这个其实我们叫这个名呢,大家可能更容易理解一下啊,就是指向运行时常量池动的方法引用啊,这呢这个呢就是从形上来看的,这个呢就是从我们真正的功能上来看啊,就是这样一个作用,行,那在这个类当中呢,我们定义两个方法啊,Public VO,这个呢,我叫method a。啊,Method a这样一个方法行,然后我再定一个方法B。
04:05
方法B,在这个方法B当中呢,我们去引用方法A。这是其一,然后呢,我们在当前类里边呢,再定一个,比如int型的一个number值十,然后在这呢,不妨我们也调用一下这个number值,比如我就做一个加加操作,调用了我们当前这个属性,好了,这个我们就完事了,此时呢我们做一个编译。编译好以后呢,咱们先用一下这个JP吧,在这块来看一下啊。杂骗。好,指定出来了,指定出来以后呢,我们现在关注一下这个message b这个方法,在这个方法里边呢,你看我们就这个算是三个事儿吧,第一个呢,是有一个输出语句对吧?哎,咱们先不看输入句,先看下边这个啊,有一个method a,我们在method b当中调用了method a,你看这个method a的调用呢,是在这儿啊,是在这儿调用,为啥我知道呢?因为你看后边给我们提示了啊呃,那另外的话呢,咱们还调了一下这个叫number加加。
05:12
那加压呢,你看它实际上是在这儿的,那大家你注意一下,你看我们这儿呢,是咱们这个最起码指令的一个指令的一个地址是吧,或者叫偏移地址了,后边呢,就是这个操作的一个指令,你看我们这个操作指令呢,叫VO virtual啊,这个呢,咱们一会再具体说这个它的指令的一个意思哈,在这一行呢,咱们调用这个一个叫一个虚的啊,就是调用虚啊,其实是调用虚方法是吧,然后这儿呢,有一个井号七。在我们调用这个属性的时候呢,Get field啊,咱们叫属性了,或者叫域字段,它这要井号二,那这两个指的是谁呢?这两个你就往上看。这呢,咱们看的是字解码嘛,对吧,在字节码文件当中啊,我们会发现有一个结构叫做content POS啊content po,这呢就叫做常量池。
06:03
诶,你记住在自解码文件当中,专门有一个区域呢,就叫做常量池。啊,就在这个位置啊,这呢,整个从这块开始,就是咱们字节码的一个初始的一个结构了,这个咱们呃说过了哈,说了好几遍了,再下一篇讲字节码指定的时候呢,咱们再详细的一点点,从前往后剖析,现在呢,咱们是基于内存的需要,需要哪儿咱们就讲哪儿啊是这样子的,这个常量池里边,你看它有好多的这种,诶我们把这儿呢,其实就称为叫符号引用。左边这块呢,就是符号了,右边这块呢,就对应了它真实的这个结构在哪里啊,当然这块呢,你看符号里边又引用符号,符号在又在下边,像这个呢,我们算是这个真实的这个结构了。那是这样的啊,那咱们刚才呢,看到了。在method b这块。咱们调用方法A呢,这叫景七,属性这块呢叫景二,好,我们先看一下景七。
07:00
景七这块呢,你看它有一个叫方法的引用,哎,这儿呢,又引用了八和井31,那八呢,这块又用了井32,井32呢看一下。那这呢,就是咱们当前的这个类嘛,对吧,哎,当前这个类啊呃,七里边八。八呢是32,刚才看过了,然后看这个井31。井31的话呢,那就掉这了,井19这个冒号井13这个这个大家你要再看就往上翻就行哈,其实这块呢,跟我们提示的景19呢,其实就是我们这个ma a,景13呢,就是它的一个返回值的类型是一个Y的啊,包括呢是没有参数的,你可以看一下啊19。19在这儿,这不就A嘛,然后呢,哎,井13。13呢,在这儿就是关于我们这样就是呃,只要呢,你涉及到的方法是wide的,是空餐的,咱们都来引用引用这个叫井13。可能我们在一个类当中啊,你想想是不是可以有很多的方法相互之间调用,有很其中有一些一些方法都是我的是空参的,那么大家都可以来引用这个井13。
08:11
那这呢,是咱们说的这个构造器的一个引用。嗯,是这样的,那么关于属性呢,刚才看到应该是井二,井二的话呢,是从八里边又掉了这个24,八呢,咱们刚才也看过了,其实就是我们当前这个类,然后你看一下这个井24。点二四在这块又掉了这个井十和井11,井十就是咱们这个number井11它表示的是一个int型的,那如果我们在当前这个类当中当中定义过很多int类型的变量,那在这块呢,它其实都是用,都可以引用这样的一个警示一表示的是int类型。诶就是这个意思啊行,那这呢,咱们通过刚才这个method b呢,这不就看到了这个方法A和这个number。咱们在这个前边这个常量池当中都找到了它相关的一个引用,一个呢,这不是景七,一个是这个景二嘛,诶属性的引用,呃,景七呢,就是这个方法的引用,这就我们这里边所说的这个问题,说原文件被编译到最起码文件的时候呢,所有的变量和方法引用都作为符号引用保存在咱们class文件的字这个常量池当中,这不是咱们就完全都看到了吗?诶这不就在常量池里边了是吧?都在这啊,你看这个除了咱们刚才说的这个方法也好,属性也好,你看字符串是吧,咱们也要用字符串,因为咱们这块不是输出了一个这个嘛。
09:29
哎,这就算是一个字符串了啊,诶这都算这个叫自变量,自变量包括呢,咱们像这个输出的,你像object,那怎么还有object呢。因为你想咱们当前这个类呢,它的副类是不是就扎我们在这个调用当前这个类的这种实例方法的时候呢,它肯定负类呢,也需要加载,所以这块呢,还有它的副类包括呢,像咱们c out,你这块输出的时候呢,这不有打印流对吧,还涉及到我们这个system。结构的一个加载。
10:00
C在哪呢,在这呢是吧,那都有啊都有就是它会把我们这个类呢,在加载的过程当中使用到的一些信息都作为一个符号呢,诶声明出来就是他即本这些符号,然后具体的你在各个方法当中,你想用谁,我们通过这样的方式呢去,哎通过这样方式呢去指明,哎就是指明这个呢,就往上一指,就知道那个常量池了,这其实就咱们所谓的这个叫哎叫什么呀,就是叫动态链接,或者叫呢这个名指向运行时常量池的方法的一个引用,就是咱们希望呢,在当前咱们这个战争当中,因为战争是咱们这个战里边的这不一个方,呃相对方法是吧,方法对应的是这个战争,它里边呢,呃记录了一个叫动态链接,或者说呢,叫指向运用式,常按传动方法引用,它呢就引用到了咱们方法区这块,先先说是咱们刚才看的资金码文件啊呃,这个。最起码文件里边这个常量池,它运行起来以后呢,就放到方法区了,这个方法区呢,既然你是运行时进来的,咱们就称为叫运行时的一个常量池就在这儿了,我们这儿呢,就能指向这儿,哎知道呢,你这块调用的这个战针这个方法谁呀,方法是它,诶是这个意思啊。
11:16
那么咱们说这个动态链接,它的作用是什么呢?就是将这些符号引用转化为调用方法的一个直接引用。啊,这个尤其咱们后边,呃,下边还会提到一些,这叫这个解析调用是吧?呃,动态链接咱们在Java里边大家都知道有这个多态的特性啊,咱们编编译代码的,或者要编写代码的时候,认为呢,是它的负类的一个方法,但真正执行的就成此类方法了,其实呢,也是源于我们这个动态连接啊,真正运行的时候执行的是谁就是谁。当然这块就更复杂一些,咱们呃,先不说这个事儿啊,这个呢,清楚以后呢,大家你回过来你再看我这个图。啊,这个图呢,我是为了方便大家更好的理解,我这呢又画了一个图,其实就是咱们刚才说的这个事儿。
12:04
这个我是放在咱们这个方法这块了。方法区这块。这个我刷新一下。嗯,放到这儿了啊,那这边呢,是咱们已经讲过的这个结构。这呢就是一个一个的都是一个线程,线程里边PD集算器,本地放火站咱们也没讲啊,先忽略掉,然后站,嗯,站里边呢,这不就是一个一个的战帧嘛,呃,这呢是我们用的这个蓝色的这一个战帧里边这个返回值方法返回值咱们还没说本地变量表或者叫局部变量表说过了,然后操作入站说过了,然后这块呢,就是我们说的这个动态链接,或者叫指向运行时常链池当中方法的一个引用地址。诶,这不就是当前class,这不就咱们这是当前的这个class哈。这个class呢,我们把它加载到这个方法区里边了,方法区呢,咱们后边会讲有类型信息,域信息,方法信息,诶其中有一部分呢,叫做运行时常量池,常量池里边呢,存储了这么多种信息。
13:07
其实呢,咱们这个运行式常量池可以提前说一句哈,它呢就是咱们刚才在这个位置看到的上边的这叫常量池。这叫常量池,这是磁接码文件里的啊,当这个常量池诶运行起来以后,通过我们java.exe这个指令运行起来以后呢,它就会把这里边这个信息啊,诶存放到我们这个方法区,叫运行师常量池的这个位置,涉及到一些这个字,这个字面量啊,比如说string的字面量,数值型的字面量,类型引用啊,属性引用啊,方法引用啊等等等等,其实这块内曼tap这不在这里都能看得到吗?对吧,都能看到就是这些信息啊,那相当于就是咱们在这个战争里边存储了一个地址,这个地址呢,就是指向了你到底这个方法呢,是谁?哎,就指向了我们运行式常量池这个位置了。哎,就是这么个意思啊,就是相当于我们通过这个区域呢,就能知道你这个方法它到底是哪个方法,诶这样子的啊,那有同学会不会说说那干嘛不在这个位置,直接把这个方法就放到这儿。
14:11
放到那儿呢,这不挺方便吗?那我们就还省了指针了是吧?嗯,为啥呀。诶,这个大家如果清楚的话,应该也知道,咱们看Java里边所有的不都是通过这个对象的引用啊,比如说这这我就简简化了哈,这是一个站,呃对象这个引用呢,就指向你对空间中的这个具体的对象,咱每次呢,都是通过这个引用呢,去调你具体这个这个对象了,这个对象呢,在对空间中就这一份,我们可以有好几个引用地址都一样啊,只要你通过引用就能掉它,你也不可能说把这个对象呢在站里边放一个,然后你回头又整一个。这就很不很不靠谱了是吧,包括咱们说这个,嗯,写小说也是一样,这个咱们说呢,这个人物是谁,张三,咱们就拿张三去称为他,你不能每次呢都把这个人真正的还得画到这儿是吧,你用张三呢去代表这个人就行,呃就呃比较方便嘛,嗯,那回头呢,我们还有其他的,这只是咱们其中的一个方法啊,那这个方法里边,哎,我也用到这个这个这个方法了,怎么办呢?哎,我还是指向一下你这个常量池里边这个。
15:14
这个方法本身本身这个结构了,然后呢,我其他战争里边还用到了,那我也是,哎,就直接指向过来就行。那这不就很方便吗?包括呢,我们还有其他的这个线程当中,只要你用到了我们这个方法,我就直接呢给你一个指针,让你指过来,就指的是你掉的是这个方法就可以了。诶就可以了啊,那换句话说的话呢,我们还有多态的特性,编写的时候呢,我们认为是父类真正运行的时候呢,还是子类呢,那通过动态链接呢,这不就更好的能够把方法的执行呢,转化成对此类的一个调用了。啊,这样一说可能稍微有点深哈,但是大家应该能明白我们刚才说这个道理哈,好,那顺便呢,大家想这两个问题,虽然咱们还没有讲这个常量值哈,说你说为什么咱们需要这个常量池呢?或者说呢,这个叫运行时常量池呢,它俩区别呢,就一个是最起码文件中的,一个是运行起来在方法区里的,对吧。
16:07
为什么需要它呢?大家想一下。没有它行不行呢?嗯,没有它呢也行是吧,没有它呢,就是咱们刚才说的,你在每一个需要的位置呢,你去放这个方法直接引用,但是除了方法之外呢,还有属性各个信息呢,像咱们这个当前这个类里边啊,在不同的方法当中,咱们都有可能掉这个属性,那我没必要每个属性在里边都给你放一个呀。是吧,都在这个战争里边放一个,这不是很占用空间吗?我们只需要呢去引用一下就可以了,哎,这样就是更更方便一些,或者说白了就是大家你看哈,咱们先不看下边的方法,比如我写一个类呢,就只有这几行代码。这几样代码你一看啊,说这个代码呢,代码量其实挺小的,但是呢,呃,当然这个小指的是我们这个确实呢,你把它这个编译以后生成的这个资金码文件啊,咱们从这来看,包括这个方法在内,看一下这个文件的一个大小。
17:05
诶张阿姨打开,诶这这个文件,这个文件大家能看到712字节,诶你看这个文件呢,确实是挺小的是吧,这个文件虽然小,但是呢,我们如果把它加载到内存当中的话呢,你会发现它其实有很多信息,比如说像这个int类型。哎,你这是system这个类,这个这个print stream这个打印流。呃,字符串是吧,对应的类包括呢,你当前这个类的一个副类等等,这些结构呢,其实都需要我们加载到内存当中,但是呢,你不能在这个字节码文件里边把这些所有的结构都写出来,那这个文件不就很大了吗?是吧,诶那总结一下呢,就是说我们自建码文件里边呢,需要很多数据的一个支持,那通常这种数据呢很大,以至于呢,咱们就不能够直接呢给它保存到这个字解码当中呢,那咱们呢,就通过一个呃这种符号引用的方式呢,去引用你相关的这个结构就可以了。
18:01
哎,是这样的啊,那这块呢,我们也写这个原因了,常量池的作用呢,就是为了提供一些符号和常量,便于指令的一个识别,同时呢,能够使得我们这个呃,文件相对来讲还比较小,那调用起来呢,直接指针指向一下会比较方便。诶,这呢,就是咱们所说的叫动态链接啊,这里边儿的内容。
我来说两句