00:00
那接着啊,咱们来看一下这个异常表的一个情况,那我们是这样来说说呢,在Java虚拟机当中啊,处理异常咱们说呢,主要是用这个catch来进行补货,它呢不是由自建码指令来实现的,而是专门呢采用这个采用了一个呢叫做异常表这个结构来完成的,早期呢,使用的这个GSR和ret呢,这个我们现在已经被dereated了,是吧,就已经被废弃了。那这异常表我们看一下,刚才呢,我们提到了,说在咱们上面这块呢,不管你是这个系统自动的抛的这异常,还是我们自己呢,写了肉这样的方式来抛异常,包括呢,我们这块像roses等等,那这样的几处内容,咱们会发现呢,都没有对应的这个异常表结构,对吧?那这里边就提到了,如果我们在一个方法当中,你定义了try catch,或者说定义了这个try finally这个结构的时候,我们才会创建一个异常表。对吧,才会创建给张表,这个我们说这个异常处理的整体的这个结构呢,叫try catch finally,但是呢,这个catch和这个finally呢,它俩是可选的,就是可以不写catch,也可以不写finally,但是呢,你不能TRY这个catch跟finally俩都不写,这不行,对吧?这个TRY呢,至少得跟其中一个呢要搭配,只要呢是有这样的这个结构,我们就会创建对应的异常表,那每个异常表里边呢,我们会保留相关的一些信息,比如说起始的位置,结束的位置啊,其实主要呢,就是我们这个你串呢,主要处理的这个逻辑开始结束的这个情况,那在这个结构结构当中呢,如果你发生了这个相关的这个异常,那我们就会这个,比如说进行一个补货呀等等是吧,跳转到我们这个catchche这个结构当中来再进行处理,或者说呢,我们这个你直接呃想这个比如说就死时就抛出去了,对吧,生成异常对象呢,没有开始抛出去的时候呢,把finally呢也得再执行一下啊这样的情况还包括呢,就是程序记录器记录的代码处理的一个偏移地址。
01:53
就是你比如说遇到异常的时候呢,呃,生成异常对象直接catch,那直接呢,就指定我们迁移的地址是哪,进行一个开始处理。
02:02
然后被捕获的异常在常量池中的一个索引位置啊,这个呢也都有,就是你到底创建的是哪一个异常类的对象对吧?对应的那个类呢,在我们常量池当中也会有记录行,这呢就是我们说的这个异常表的这个基本信息,等一下呢,咱们一看代码大家就知道了。然后下边呢,这块呢,内容相对来说比较简单一些,咱们的代码也都写过了,对吧,就是说呢,我们不管抛出什么异常,只要呢,你异常处理的这个catch这块啊,匹配的相应的这个异常类型啊,这个也存在一个多态性,对吧,你创建的是一个异常的子类的对象,那我们这个是一个负类的声明也可以catch住。那一旦catch了,我们的代码呢,就可以继续向上执行,那这就没有问题对吧?那如果还有finally情况什么样子呢?这个咱们一会儿也是看自己码文件,那看这个具体的资金码,这个情况咱们来进行剖析,上面这块说的情况呢,就是说如果呢,我们发生这个异常了。然后这块呢,假设你也写这个try catch,假设你catch的这个呢,比如说咱们针对的是这种编译式异常,你catch了,结果呢,我们TRY里边呢,发生了一个运营是异常,没有对应的catch语句,那这时候呢,相当于我们没有找到一个匹配的这个这个exception对吧?那这个时候呢,我们会强制的结束当前的方法,并且呢,当前这个战争呢,也会被弹出。
03:21
也会被弹出,那这个异常的对象呢,就会抛给他上一层这个战争的一个调用者,那可能是上层的方法了,对吧?那如果上层的也没有找到合理的异常处理方式呢?这个线程就终止了。这个线程的就终止,相当于就是呃,比如我们这个线程当中,一个战争,两个战争,三个战争三个方法对吧,然后最上面这个方法呢,抛出异常对象,自己没有catch,那他就抛给我们下边这个方法了,这个战争呢就弹出去了,他呢也没有处理,他也就出去了,然后再再抛给他,他也没有处理,然后这个也出去了,整个这个线程这不就结束了吗。很正常的对吧,那如果说呢,我们这个线程呢,是最后一个非守护线程,那我们GM呢,自己也就终止了,因为咱们知道GM当中呢,必须得保留一个非守护线程,那如果要是只剩下守护线程的话呢,我们GVM呢就会退出,对吧?就好比是我们说的这个main线程,主线程退出了,又没有其他的这个非守护线程,那GM呢就结束了。
04:18
行,这个呢都相对来说比较好理解,下面呢,咱们重点来看一下这个异常表的一个情况,那比如说我们这里边就看一下这个叫try catch这个方法,好,这个咱们打开这看一下,行,这是这样的一些相关指令,对吧,那这个呢,相对来说长一些,已经呢涉及到这个异常表了,咱把这个呢CTRLC一下粘出来,咱们在这呢做一个分析。好这个粘过来,这个呢比较长,咱们不行把它就截两段。行,这个稍微放大一点。
05:03
好,那么这个再再稍微往这拽一拽。行,然后呢,再把咱们这个代码呢,给他盯一下。来我们这块呢,做一个分析,从这个代码层面的话呢,我们这是创建了一个file类的一个对象,然后把这个对象呢,放到咱们file input stream这个方法的这个,呃,这个构造器的这个参数位置,那在我们这个new file input stream这块呢,会出现一个可能会出现叫file not found exception,对吧,但是这块呢,我们是一个编译式异常,咱们就要显示的进行拆开的一个处理。嗯,对吧,是这样个场景,那这块解释的话呢,你看我这里边写了两个这个catch,写了两个catch对吧。行,那这呢,咱们就按照这个顺序呢来进行剖析,首先的话呢,这里边儿上来呢,你就拗了一个file,所以这块呢,你要拗个对象,这个对象呢,我就写到这了。
06:02
0X,比如叫1122,这个呢,首先都是黑体的。这个注意122呢,他们它其实对应的我写到这儿吧,是咱们这个file类的一个实例,这个注意是你真正创建那个对象呢,是我们推空间把这个地址呢给到这儿,行,然后接着有个damp,就是我们所谓的这个叫复制,然后再接下来呢,这个叫LDC,呃,将字符串这个常量池当中,我们取了一个这样的一个字符串,就是D盘下的这个哈,这样一个数据,对吧?这个数据呢,咱们前面也提到了,本质来讲,本质来讲的话呢,这个数据不是说放在这儿的,还是放在咱们这个字符串常量池当中,对吧?这块呢,记录的是个地址值,那这块我我我我写成个地址值吧。要不有同学呢,这块可能会理解上有有点问题啊,咱们上一节呢,其实也说到说到这个事儿了,这个放的还是地质值,只二零类型的都是地址值。接下来的话呢,我们叫VO special调用我们这个file呢,叫类实例构造器方法,那这个时候呢,我们顶层的这两个就出战了。
07:02
这个颜色太浅了。行,他俩呢,这就出战了,出战以后呢,就是配合我们这个类实力构造器方法呢去使用,那你该给人家这个初始化就初始化,对吧?行,然后呢,把我们这个还剩下的这个数据呢,叫a store呢,下线一就是保存到这儿,那就是0X啊1122,那就在这儿了,这个呢是咱们这个file类型的,前面这个呢,还是咱们说的当前这个try catch这个方法的,嗯,所在类的这个实例,对吧,这也是一个地址啊行,那再接着往下走,又一个new,这个我们需要用的是five input这个类型的一个实例,比如说叫A0X2233。那嗯,这个呢,对应的是咱们叫。Input。Stream对吧,这个类型的一个实例,那就放这儿了,然后接下来又是一个dump。嗯,没问题,然后呢,Lo的一个一给咱们保存一下。
08:01
Lo一个一接下来的话呢,把我们这个这个位置上的这个地址呢,再给它,哎,这个咱们刚才把它是不是保存到这儿的时候,这个也相当于就没有了,对吧,就是在我们这个操作的时候啊,这个刚才忘了把它变色了行,然后呢,你把这个ALO1呢,现在也加载过来,把这一个0X。1122行他就过来了,现在是这样个场景,就是这一步,那再接下来的话呢,叫VO special,然后我们调用的是file input stream的叫类实力构造器方法,那相当于是把这两个参数就都出了,对吧。嗯,出站呢,配合呢去创建,呃不是创建呢,就是对我们当前创建的file input STEM这个类的实例呢,进行一个初始化啊初始化你这呢,上到这个参数给相应这个类中的这个字段呢去赋值了,对吧?行那完事,那再一个呢,就a store下游线二就是把我们这个数据给它保存在这儿。那它对应的是file input stream这个类型。
09:05
这块呢,我只是做一个标识,所以写到这儿了,那相应的这个位置呢,他也就出站了。行,那目前的这个效果呢,整个就是这样子的,嗯,这呢,就是我们对应的这一边儿,这就结束了,那重点呢,我们来看这一边里边这个情况。整体上来看的话呢,通过这个代码层面,大家看不到说拆开怎么在这里边似乎没有什么体现是吧,那咱们分析一下,那上来的话呢,先一个LDC这个hello,主要呢,就是咱们下边多了一个额外的这个操作。多来一个这个操作,我把这哈呢放到这儿,其实放在这儿还是那意思,嗯,真正放的呢,其实是一个地址对吧。那具体这个数据呢,是在咱们这个最串常量池当中,那0X,比如说4455。嗯,放在这儿了,然后呢,A store_三把这个呢,保存在我们这个这个位置上。对,那相当于应该是4455啊,是他那这个呢就出去了。
10:00
嗯,那这呢就指向了我们常量周抓常量池里边的一个哈,对吧。那这个保存到这,然后接下来叫GOTO383822加16得到的啊,直接呢,就蹦到38就到这儿了。嗯,到这儿呢,就相当于是我们这块就结束了,是这意思吧,那相当于这块我们就结束了,那这个时候呢,内存中的结构这块呢,是没有数据了,然后在我们这个这个就变量表当中呢,是有这样的四块。对应的这个数据行,那这个呢就结束,然后说下边怎么还有呢,这个咱们蹦到的是这个38,直接就蹦到这儿了,中间这一块。是不是在这个位置啊,咱把这个颜色呢,稍微的变一下。行,我变成这个颜色了,对吧?好,那我们如何看待这一段操作呢?那其实就涉及到我们可能会出现的一些异常的一些情况了,异常的一些情况,好那这个代码呢,咱们没有出现异常,那就是这样子的,然后呢,我们过来看一下这里边的。
11:01
这个就是我们说的异常表。嗯,行,我这个往上移一下。这样子来看行,那么这个时候呢,你看我们这个异常出现呢,从零到22,从零到22呢,是就是不是就从我们这个开头,就是你在这个踹里边,我们一开始进入一个file的时候呢,这不就零吗?22呢,其实就正好对应到我们一最后呢,是不是要结束的这个位置了。那就从零从零到22,就是整个呢,咱们这个踹当中的这个代码的这个结构。嗯,踹中这个代码机构,那从这个到22这个范围之内呢,如果你要出现异常了的话呢,我们这里边儿有对应的一个叫25,一个呢叫33,那25呢,这块对应的是我们常量池这个井14这个是对应的是景二,那我就不具体去看咱们常量池了,你要看的话呢,14里边对应的类型就是not found exception,这个呢,对应的叫runtime exception,因为我们这里边是不是写了两个catch,所以呢,我们的这个叫异常表里边就有两个结构。
12:06
那就有两个结构,那也就是说呢,如果我们在零到22这个代码的执行过程当中,如果你出现异常了,那出现异常了,这个异常的类型呢,那我们跟这块file not found exception这个类型,你看catch的类型嘛。那如果你发现这个你里边系统自动创建的那个异常类的对象呢,是file not放seven这个类型的,这里边儿是存在多态性,就是以向上转运的方式,如果跟它匹配上也可以,那如果是满足这个类型的,我们这块呢,就到25这块了。注意就到25这块了,那这个呢,场景描述的是什么情况呢?就是说前面这个在执行的过程当中,当中如果你出现异常的时候呢,这个我们直接呢,就蹦到是不是25这儿了,就蹦到这了,对吧?嗯,25这块做的什么事呢?叫a store呢,下游线一,那我们这块呢,是handle是catch的,Catch的什么呀,Catch的其实那其实这块呢,中间这些过程有可能在某个环节是不是就没有了,对吧?这是我们刚才分析的是没有异常的情况,那这块atore,其实这时候呢,我们会,呃,相当于得到一个异常类的一个对象。
13:14
这个异常类的话呢,以我们发生这个类型的为例,那就是file not found。Exception了对吧,就是这个类型的一个实例,这个实例呢,它有个地址,比如叫7788。啊,就得到这个地址,然后呢,诶叫a store_一,相当于我们把这个实例呢,就给存到了这个位置上了。注意这块咱们说的是什么,是你可能会出现异常的这种场景,那咱们这样,我把它呢,CTRLC一下,咱们在这块呢,我CTRLV再再复制一份啊。然后我把这个数呢擦掉。嗯。嗯,我我我这样把它复制一份。
14:00
重来。就有一个间隔行,那这个时候的话呢,我们这个位置其实放的就是这个0X7788了,就是不是我们上面这个场景了,那这个0X78就放到这儿,那对应的是不是就塌了,那放完以后呢,这个它就接着呢就也出战了。然后再下边的话呢,我们叫lo下二选一,相当于把这个027788呢再放回来。哎,放回来了,放回来以后,然后接着呢,我们叫这个invoke virtual,相当于此时调用的就是file not found exception这个实例的叫print stas,因为我们这调的不就是这个方法嘛,那此时呢,这个实例呢,出去,然后调用这个实例的这个方法,那这个呢,相当于就也出账了,那相当于我们这里边就做了一个这样方法的一个调用,对吧,调用完以后呢,又是GOTO38啊直接呢就结束了。这呢就是我们如果发生的是这个异常类型的时候呢,诶咱们就是进来的这个情况,那如果发生的不是这个异常呢,那就相当于我们在这块呢,在handle豆的时候发现呢,诶不是这个类型,那我们看看是不是这个类型呢,如果是这个类型的话呢,咱们在零到22这个范围之内呢,就直接蹦到33。
15:09
相当于刚才这个事儿没有发生。理解吧,就是我们在上面出现异常了,发现不是这个类型,是这个类型直接就到33了,33呢这块呢,A store1其实跟我们刚才这个过程有点像,只不过这时候发生的呢,是咱们这个runtime。Exception这个类型,当然了,也可能是它具体的一个实例啊。我把这个再这个稍微的调一下。Exception对吧,然后这个呢,咱们也赋个值,比如0X叫8899,那这个0X8899呢,就放到我们这个位置上就不是它了,这就是另外的另一种情况。0X8899行放的就是它对吧,然后放到这以后呢,它这个数据呢,是不是正常的就也就消失了,然后接下来33该34了,把这个0S889呢再拿过来。
16:00
嗯,再拿回来,拿回来以后呢,接下来也去调用一下你这个实例的print sta这样一个方法,那调用方法的话呢,他就也出战了,那完事以后呢,这个就不用goto了,因为它已经在最后,所以直接return结束。能行吧,那这里边儿呢,我们看到了,就是在咱们的代码层面呢,咱写了track开,但是在我们这个自解码的这个情情况呢当中呢,其实你似乎看不到我们这个TRY和cash对应的这个自检码指令,因为本身呢,是不是也没有啊。咱们这说了是不是不用这个四级码指令来处理的,而是呢,采用这种异常表的方式,在你这个踹的指定的这个范围内,我们有开始有个结束,你发生相应的异常了,就会对应创建相应的异常类的实例,那我们在这儿呢,去匹配,呃去匹配这个类型跟谁匹配到了,我们就呃跳转到你相应的这个偏移量的位置呢,去做一个接下来的这个指令的一个执行,那就可以了,这呢就是咱们说的这个异常表这个情况。好,这呢是一个比较典型的一个这个场景,刚才咱们分析呢,花了一定的时间,行,那下边呢,咱们来看这样的一个问题,那以前有同学在学习这个Java的时候呢,有一些困惑,就是关于我们这样的一个场景,在面试当中呢,也出现过这样问题,有同学呢就懵了。
17:14
好,咱们分析一下。这个题目呢是这样子的,我这呢写成是个静态方法了,定义了一个字符串叫hello,然后在这个TRY里边呢,我们去return一下这个字符串。那按说的话呢,我们就该结束当前方法,但是呢,咱们说有finally finally呢,我们说是一定会被执行的,对吧,那在finally当中,我们给HR呢,又重新附了一个值叫艾特硅谷,然后接下来呢,你再再执行的话呢,是不是就该执行这个叫return了,那问题就是我们这个放个方法得到的是hello呢,还是爱特硅谷呢?这个,如果要没做过这个题目的同学,可能还真是哎,懵了。那做过的话呢,这个结果呢,应该是能说出来,但是呢,解释过程不一定清楚。这个结果是hello。
18:01
也就是说咱们这卡。那有的人会想,那这个难道没执行吗?这个也执行了,但是你可以理解成这是一个复制品,我们现在返回的呢,是最初的那个IR。那这个代码层面,咱们该怎么去看待这个事儿呢?那其实咱们要看的不就是这个放里边这个code,它的这个操作吧。你看我们这里边没有catch,是try finally也会生成这个异常表,对吧?哎,咱们主要呢,就看这个结构就行,好,我把这个呢,CTRLC一下咱们粘过来。把这个代码呢,咱们也盯一下。行来来,咱们这个来做一个分析,首先呢,这个l DC hello,行hello呢,就是要进来了,其实本质上内容呢,这还是哈,这个呢,咱们还是按规范一点写,写成这个地址。
19:08
行这就OK了,对吧,然后接下来的话呢,叫2STORE呢下发现零,那这个呢,放到零的位置是因为咱这是静态的,然后可以呢写成静态了,要不咱以前都非静态第一个位置都Z,现在你知道静态的第一个就没有Z了,那直接呢把这个0S112呢就放到这。对吧,没问题,然后放出来以后呢,这个呢,是不是就对应的就。哎,弹出站了是吧,再这样呢,叫lo的下限零,那就把这个122呢再拿过来。嗯,又过来了,过来以后的话呢,叫a store呢,小一,诶把这个呢又复制了一份。嗯,这个呢,主要特点呢,就在这儿,那它这个也出战了,行,这个我们就执行到这儿了,再接下来呢,叫LDC引入了一个叫爱硅谷。对应的,你自到长远池里边叫爱硅谷,这呢叫0X,比如2233。好,嗯。
20:00
到这了是吧,然后接下来呢,叫a store呢,下划线零,你看a store下划零,把我们这个0X233呢,诶保存到这儿,那保存到这儿的话呢,相当于把这个112呢,是不是就给干掉了。把它给擦掉是吧,那擦掉呢,就换成了0X2233,那这个呢,相应的他不就也出战了。注意你看这时候比较重要的一个操作就把它给换了,这个过程呢,其实就相当于我们这定义完它之后,这块呢,按说该return了,但return之前呢,我们这有finally类的操作,Finally操作呢,这块艾特硅谷就修改了你这个I7R它的这个值,但是你看我们这呢,是不是还存着一份它呀,一份hello,对吧,好,这是改的是这个位置。行改完这个位置之后。然后下一个叫lo的下线一,那把这个呢,是不是再加载过来。0X1122。那就到这儿了,然后呢叫二位称啊,二位称呢,不就是把它给返回吗。对吧,嗯,把这个返回,那这个指向呢,是不是就是我们这个hello啊,所以说呢,咱们这个方法呢,咱们去运行它的话,嗯,这个结果呢,就是hello,你看能理解这个过程吧,主要呢,在这里边我们看到了它相当于是那个a store1a store0,这相当于是得到一个这个str的一个复制品,然后我们修改的话呢,是你最初的这个位置,但是我们现在是把你后一个这个就是人家本身要返回的这个呢,在加载的操作入站当中,还是原来的这个,然后返回了。
21:28
啊,是这样一个场景,然后这块的话呢,是不是就咱们多余的这个相应的这个部分了是吧。哎,多余这个部分,然后对应的咱们这个那异常表。嗯,一张表,你看这块呢,这个场景这个三到五,三到五。就是这一块是吧,这一块呢,看做的就是咱们这个踹里边的这个核心操作。你看TRY里边这个操作呢,我们要准刺了,你看这时候相当于是又帮我们把这个一开始那个位置加载过来,咱又复制这一份嘛,那就是这个复制的这个操作,那就给他复制到角标一的这个位置了,三到五的这个部分,如果说这个位复出来呢,要出现异常的话呢,我们就这个诶可以是任何类型,咱没有具体描述嘛,你要出现的话呢,直接就蹦到这个十这了。
22:16
啊,根据你产生的这个异常的这个类型啊,这呢咱没有具体的catch嘛,就安是吧,那安妮,然后这块的话呢,我们就把这个异常类的对象呢,呃,先你要真正出现异常类对象呢,这个对象就先放在这儿了,然后接下来的话呢,把它保存在咱们这个,诶角标二的这个位置放在这儿。然后的话呢,按正式来讲说,哎,这不该出去了吗?不行,那你这时候呢,是不是还得去这个执行这个final里的这结构啊,刚才咱们说是三到五吗。对吧,三到五的这个过程当中出现的,那其实这个时候呢,我们准确的来讲呢,就是这个finally这个事儿呢,还没做呢,所以下边呢,你看把这个finally这个事儿呢,爱在硅谷该放进来还放进来。诶,放进来,这是ID硅谷对应的这个字符串的一个地址,然后把它呢,再保存到这个A0的这个位置上,就是你最初的那个IT2的那个位置上。
23:07
然后呢,再把我们这个二的这个异常类型呢,再加载过来,然后再A肉,相当于这个抛出去的是一个异常类的对象是吧?哎,就是这个过程行,那这呢,我们就分析出来了啊,为什么这个结果呢,还是hello啊这个大家呢,清楚一下就行啊,那么咱们讲这个自检码指令呢,基本上咱们也渐近尾声了,那通过咱们这样一组一组的去讲解这个我不知道大家呢,有没有一个这样的一个共鸣什么呢。就是原来呢,咱们很多在代码这个层面看不到的东西,那确实呢,咱们呢,是不是通过自检码指令看的就更加的全面和细致的包括呢,这里边我们没有谈到,像这个集合当中为代表的咱们有泛型的结构,那泛型这个结构呢,我们在实际加载时候呢,就存在泛型的这个擦储问题,那大家呢,也可以写写相关的这个代码呢,你看一看这个词解码方面的一个执行是什么样子的。
24:02
那这个呢,其实真正的是把大家从这个最底层的这个功底上啊,那做了一个提升,以前的时候呢,你看这些东西呢,你感觉跟乱码似的,那现在的话呢,它里边有非常明确具体的步骤和含义。啊,对于我们在理解这个代码呢,应该具有很大的这个帮助。好,这呢,就是咱们说的这个叫异常表的这个情况。
我来说两句