00:00
好,那关于虚方法和非虚方法呢,咱们就告一段落啊,说到这儿,包括这个引VO dynamic这个指令呢,咱们也解释清楚了,然后呢,在我们讲到这个续方法的时候呢,诶,咱们再重复的提一个概念,诶就是叫做方法的重写,因为方法重写的出现呢,诶导致呢,我们出现这种续方法一种调用方式了,呃,因为咱们也看到像前面提到的这样结构呢,主要呢,是因为他们不存在方法的重写了,对吧?那么关于方法的重写呢,咱们再来强化一下。说Java语言当中方法重写的本质到底是什么呢?哎,大家看找到操作数占点的第一个元素所执行的对象的实际类型啊,这就涉及到当我们去调用一个对象的方法的时候啊,调用一个对象的方法的时候呢,咱们会将这个对象呢,首先呢是压入操作数站。诶,然后呢,根据自建码指令,通常呢都是invo virtual,诶根据这个指令呢,咱们去寻找这个类型的实际类型啊,这个实际类型呢,这里边就记作了C是吧,记作这个C,然后如果呢,在这个类型C当中找到了与常量中描述符诶简单名称都相符的这个方法,就我要调用这个方法到底是哪一个呢?诶这个按照这个常量池当中这个名字的描述呢,都一致了,那我们接下来呢,去进行访问权限的一个校验,看一下是不是有权限进行调用,如果有权限呢,我们就把它转化成直接引用啊就调用了,这就正常结束,那如果要是不通过。
01:28
相当于呢,就是我们这个权限要是不允许的话呢,就会返回叫illegal access error,非法访问的这样的一个error,哎,这个呢,是由于我们这个权限影响造成的。啊全影响造成的,否则否则的话就是如果我们在这个呃类型本身这个C当中啊,如果没有找到跟它相符的这个方法的话呢,我们就依次呢,向上去找这个C的负类,这个负类呢,继续按照咱们说的这第二步去执行,如果找到了权限不够就报异常,如果权限够哎就正样执行,如果呢,在它的直接负类中没找到呢,再接着去呃直接负类的负类中再去找,那最终呢,如果也没有找到合适的方法汇报呢,叫abstract method error,就是既然呢,我们能够呃看到这样的一个方法的一个常量了,对吧,那最后呢,发现没找到,呃一直呢找负类都没有找完,那肯定是由于实现的是这个接口中的这个方法了,那这个接口中的方法呢,因为你也没有重写嘛,所以呢,就导致呃,你调呢,实际是一个抽象方法了,诶就是这个意思啊,然后这里边的话,我们这个abstract method error呢,比较好理解,哎,刚才我也解释清楚了,你要是重写过了,总会在上面找到这个重写的这个方法,如果一直到它的顶头的类。
02:41
T当中都没有找到,那一定是因为你实现的是接口了啊,那这个接口中你要是没都没重写过,这不就是调用的是抽象方法了吗?这个异常好理解,那前一个呢,叫非法的access error,前面这个很清楚啊,非法access咱们在运行的时候呢,也会见到一个,诶非法的access exception,哎,这样的一个异常。
03:02
啊,其实它这个编译是异常啊,就是我们这个try catch处理完以后呢,在运行时可能会出现的是一个exception,这呢是一个error,它俩是不同的这个异常情况,那关于他的介绍呢,我们这说说程序呢,试图访问或者是修改一个属性,或者是在调用一个方法的时候,那这个属性或者方法你没有权限访问。啊,一般呢,这个会导致编译期异常发生在运营的时候呢,也就说明发生一个不兼容的一个改变了,不兼容造成的。哎,这个稍微有点迷糊啊,就是前面这个权限的影响呢,大家是比较清楚的是吧?嗯,比如说呢,本来在我这个炸包,我这个炸包呢,是放在跟class在一个包内的,呃,这个访问权限呢,我用的是一个默认权限的啊,这个是都能够访问,但是我现在把这个炸包呢,我放在包外呢,再去运行就会出现这样的一个非法访问的一个error。啊,这种情况经常发生在什么场景呢?大家呃,这个我之前也在这个,呃,百度上也见过这样的啊,因为有学生去问嘛,是吧?呃,这个错误呢,一开始刚见到的时候呢,还挺不容易去排的哈,一点点的去去找,呃最后呢才找到了,然后呢,就是因为咱ma文呢,都用来管理这个炸包了,那很多时候呢,在这个炸包方面呢,会存在这个冲突啊,有时候你是重复加载了或者关联的炸包呢,跟另外的炸包呢,关联的这个你的版本号又不一致啊这个等等一些情况呢,最后都导致我们出现叫非法的XXL,这个咱们得具体情况具体分析了啊,出现这样一个异常的话呢,其实得小心一点啊,比较不太容易的去去找啊,就是ma文这个炸包的一个冲突,这块出现的问题啊行,这呢是我们说的这个方法重写的一个本质啊,就从我们这个实际变量的你调样这个方法,这个变量的这个类型,我们开始去往上依次去找,哎,这样的一个过程啊行,那这呢又提到说在面向对象的变程当中。
04:54
会频繁的使用到动态分配分配,呃,就你可以列解成就咱们这个invo,呃,Virtual是吧,然后每次调用的时候呢,都会重新在方法的类,方法的类的方法原数据当中去搜索合适的目标,就每次呢,如果都要是实现这样个过程啊,找一下这个实际类型,往上找找找找,下次又掉又得找找找找找,每次这样找的话呢,非常的麻烦,说比如说你要调的这个方法一,他自己没有找到它的副类,副类没有再找到它的上层,副类找到了,那以后我们调的时候,能不能每次都去它的上层的上层去找这个方法呢?就直接记录上,省得每次都去找了,对吧?诶这里就提到了,说为了提高咱们的性能啊,在方法区咱们建立了一个叫虚方法表。
05:36
虚方法吧,为什么是虚方法表呢?分析方法不需要表吗?大家想想需要吗?飞絮方法不需要对吧,因为飞絮方法呢,咱们前面也提到了。找一下这个PPT分析方法,主要就是这些方法嘛,复列方法,因为他已经非常确定的,你调的就是哪一个方法了,所以直接就找到它了,对吧,不像咱们现在所说的这个续方法,我得依次呢向上去找嘛,每次都往上找,可能得找好几次,呃,找好几趟才能找到,那因为这呢也存在一个小的循环嘛,对吧,那那所以这块呢,我们才为了能够提高这个性能啊,减少这样每次都去找,所以呢,建立了一个叫虚方法表啊,虚方法表里边就不存在这个废墟方法了啊。
06:23
它就不在里边了,那么呃,这个续航表作为我们实际方法的一个入口,就是你真正要调用相应的这个对象的时候,这个对象的类型是是什么确定了,然后直接呢,我们看一下你这个呃,Invoke virtual这个方法直接呢,对应的是调到谁?呃去去续方法里,方法表里边去找了啊下边呢,是说明这个虚方法表呢,什么时候创建呢。什么时候创建呢?这里提到呢,是在类加载的一个链接阶段呢,来创建的链接阶段,咱们说又分成了好几个细节的过程是吧,那具体来讲是链接阶段的哪个过程呢?我们看一下这个类加载此系统。这是咱们之前已经讲过的,对吧?当初咱们在讲的时候呢,其实就在解析这块呢,呃,稍微的这个讲的不是那么透彻了,因为相互之间跟咱们后边内容都会这个联系在一起,呃,这时候呢,我们翻回来再看,你看是不是就更清楚了,解析的时候呢,将常量池中的符号引用转化成直接引用,哎,咱们讲这个方法调用不就是符号引用转化成直接引用嘛,诶那就是在我们链接当中的这个解析环节中出现的,然后这个符号引用呢,包括像类的符号啊,属性的符号啊,方法呀符号啊等等都会有,对吧?诶咱们在这个看这个自解码的时候呢,这不就是属于,呃这个这属于方法的符号了,这属于这个诶属性的符号了,像这个就属于我们对应的这个类的这个符号了,对吧?诶都需要对他们进行一个转换,哎,就是在这个解析环节当中出现的啊。
07:50
行,这就是我们解析环节中出现的一个循环表的一个创建,然后下边呢,我们来举一些这个例子啊,通过两个例子呢,让大家来理解理解一下,呃,这呢,呃是这个在网上直接有这个线成这个图了,我就不再去重画了啊这个也比较清楚的能够表达这个事情,嗯,我们这呢有两个类,一个叫father,一个叫做丧,这个丧呢是继承于father了,哎,是这样的,嗯,然后father呢,是继承于咱们的object,然后呢,这个father重写了两个方法,一个呢叫hard choice,一个呢叫那这个叫hard choice是吧?诶这两方法呢,这个参数是不一样的啊,诶相当于两个重载的方法,然后呢,这个S这个子类呢,它重写了father里边的这两个方法。
08:32
重写过了啊,重写过以后呢,其他的方法都没有重写,那我们各自father跟这个sun它建立的各自的这个续方法表当中呢,呃,像这些没有重写的这种方法呢,这都是指向的,就是它的各自的,这应该是sun的负类的负类了,对吧?也就是你这个sun如果说在你这个对象的执行过程当中调用过,比如to string,你没重启过,你复列也没重启过,直接调到那直接呢,我们在这个续航表中呢,就指明你这个to string呢,就是直接指向object,这样我们再去调3.tostring的时候呢,直接就这样跑到这来了,用不着再往上层,再往上层去找了。
09:09
哎,是这个意思啊,那因为你重写过了,所以说这两个方法呢,虚方法表中指向的话呢,就都是你自己这个类型的,诶father呢,呃,它这个自己的方法嘛,它就指向这两个,其他方法也没有重写,那就都指向father的负类,诶这个比较清楚啊,行,那我们再举一个稍微复杂一点的例子。这个例子里边呢,我们涉及到这样的几个类,首先呢是一个dog,哎,狗,然后呢,这是dog的一个子类啊,这是一种特殊的狗,叫可卡犬。哎,可卡犬这个很多女生喜欢这种犬啊,诶就是英国的这这种一个一个这个卷毛狗啊,其实我觉得中国这种我们叫中华田园犬是吧,这个名字很霸气哈,我觉得就挺好的啊,智商还挺高啊,嗯,这个呢是这个猫,诶这个猫实现了一个叫friendly这样一个接口,然后这个可卡犬呢,也实现了一个接口,同时它还集成1DOGOK,这是这个结构,那对应的呢,咱们这个代码我是写在这个JAVA3这里边了啊,打开以后,诶整个都在这接口里边呢,咱们定义了两个方法,叫say hello say goodbye。
10:15
我看我这个结构能不能给大家这么着一下啊,方便呢,大家去理解。嗯,我先这样一下。从这到这儿就是这个里边的方法细节呢,我这就没有再去提供了,因为我们主要呢关注就是这个方法有没有重写呀,是吧?呃,这个实现了呃接口,那这个接口里边方法重启了多少等等这样的一个情况,这样呢,我就放在这很方便大家看咱就行啊,这个再往上一点。好,那我们来看一下这个,这还挡住了。这个放这儿吧。我们看一下这个dog,它的一个续方法表,这个dog呢,咱们是在这是在这这个dog里边呢,重新,呃这个有两个方法的声明,Say hello和to string行,那么你看这个dog to string,呃,Say hello say hello,它自己写的,然后呢,To呢,它是呃重启了object,它的负类呢,直接就是object了,所以这两个方法呢,指向他自己,那剩下这些没有重写的呢,就指向它的副类,这是它的这个循航表,所以当我们再去调用的时候呢,如果你调的是这个白色的方法,直接呢,就用自己的蓝色的方法,直接用它的弗类的啊,这个徐方法就不用你再去一层一层向上判断了啊好,再看下边这个呢,是咱们这叫可卡犬在这。
11:35
这个科犬呢,看一下啊,嗯,它实现了这个接口,接口里边有俩方法,Say hello say goodbye say hello say goodbye重写了,所以这个都指向他自己,然后呢,他记承这个dog,嗯,Dog里边呢,Say hello,诶这个你看dog里边有个say hello,那不好使了,你dog里边say hello,咱们这个他自己重写过了嘛,呃,这个一方面呢是对负类方法的重写,另外一方面呢,也可以理解成对方法,诶负附这个接口的一个方抽样方法的实现啊,总之呢,人家这个c hello呢,就用自己的了啊,不再是用它的这个,这还有一个类呢,是吧,不用这个了啊,然后呢,这个继承的这个类当中,Dog里边有一个two string,诶这个two string,所以呢,你看就出现这样情况,当你要是掉的say hello say goodbye呢,就用的是咱们这个可卡犬它自己的这个方法,如果你要two string呢,它自己没充血掉它的负类do里边的。
12:28
啊,这是这个红色,你看特意特意标识出来了,然后其他这些方法呢,用的都是object的。哎,这个比较清楚了,就这个续航表一旦指命以后呢,当我们真正再去根据你压入操作数站的这个对象调方法的时候呢,是谁就直接指向谁,用不着在一层层向上判断啊,你掉to string啊直接就指向这不再去它里边找了啊然后再往下这呢,我们看这个猫猫呢,在这猫呢没有实现没有直接的这个负类了,直接就集成一个了,呃,然后呢,它重写了这个eat say hello跟say goodbye诶这三个方法,诶这个这边的诶稍等啊呃这边的嗯,Eat say hello say goodbye啊这三个方法他都呃人家重写了,所以都指向他自己,嗯然后呢,这个two string,嗯,Two string,诶我这块呢,还没标识这个two string是吧。
13:20
这个里边呢,我这插一个方法啊,这个注意。哎,这呢,应该补一个这样的方法,哎,这就可以了啊,那我们把这个图呢,再重新的再截一下。诶,这个呢,才是我们这个正确的一个情况啊,诶这是关于我们这个cat了,你看这个cat里边呢,这个兔死缀呢,它也,诶这个这个这还报个错呢啊诶我们先做一个return啊看哎这么着啊,行诶我们回过来就行,这也不影响我们看这个方法的整体结构了,嗯,Two string这块呢,我们也做了一个重写,那重写以后呢,包括这个finalize这个方法后面呢,咱们讲这个垃圾回收,那垃圾回收的时候呢,如果我们重写的这个finalize,他在判断这个对象能不能被销毁的时候,这个呢是有可能,诶不会被销毁的,这个咱们到时候再讲啊,一般情况下呢,咱们这个方法不会重写,那现在我重写了,那既然你重写了,这里边呢,Final lines跟to string,诶这都指向你自己的,然后呢,这个你自己又定义的这三个方法也是你自己的,剩下这方法都指向你的类的。
14:29
哎,就是这样个情况,哎,这个也比较清楚啊,哎,注意这块呢,呃,兔子圈这个方法,根据这个图往回推,这块呢,这个得补一个这个方法啊。好,哎这呢就没有了,哎整个呢,通过我们刚才说的这两个例子,哎,大家呢,去体会一下,咱们说的这个叫虚方法表,哎主要呢,起源就是在于咱们刚才提到这个方法重写的一个本质,呃,依次往上找,这个事儿不太靠谱,呃能够更快的去找到你要调用的是哪一个结构中的方法呢,我们建立了一个虚方法表,通过刚才两个例子呢,给大家做了一个演示啊,应该是比较清楚的,好,那么整个呢,咱们关于方法调用这块呢,就算是说清楚了啊,应该呢,大家对实际方法调用呢,有一个透彻的理解了,就虚拟机层面指令是什么,它是怎么还这个。
15:15
层层的找到他想调用的方法了,怎么能够提高他这个调用的一个效率,呃,这个咱们都做了一个说明啊,那整个咱们关于这一章里边,其实最这个虚拟站这一章里边啊,最重要的呢,局部变量表操作数站,还有咱们的方法调用,诶咱就算是介绍完了啊。
我来说两句