00:00
行,那上边这个面试题啊,咱们就说到这儿了,哎,大家呢,这个结论呢,如果在后边面试当中遇到这样的情况呢,那一定要回答就是我们这里边写的这个场景对吧?那么下边的话呢,咱们呃深入到里边呢,再来谈一谈,看一看呢,如果说这个拼接符号呢,左右两边,咱们上边呢,是提到过这样的情况,就是说它是呃常量的时候,这呢没啥可说的,就是呢,编译器优化直接呢,我们底层呢,就是放了一个ABC在自符串常量池里边,对吧?那么针对于我们说左右两边呢,如果有变量的话。有变量的话呢,咱们说它就是新造的一个对象对吧,这个对象呢,相当于是我们在这个呃,对空间里边是new的这样一个场景,那么呃,在这个new string这个场景之前,它里边有没有一些细节问题啊,实际上呢是有的,那我们来看一下。这呢就是一个典型的问题,当然从这个结论上来讲呢,这个大家呢是非常清楚的,我们这个S3啊,它就是个自物差常量池里边的AB,那么S啊这个是两个变量呢,做的一个连接,或者叫拼接,那很显然呢,我们提到过了,它是新new的一个,那很显然它这呢是不是就是个false啊,结论的话呢,实际上就是我们上面讲这个面试题呢,已经说到了,但是呢,关键呢,我们要理解一下说呢new论是吧,这个new论是怎么出现的,具体的细节情况,下边呢,咱们来讲一下这个问题。
01:21
那这个问题的话呢,其实也非常容易的去说明,大家呢,只需要呢,把我们当前这个程序呢,给他做一个预编译之后呢,其实已经预编译过了,咱们刚才那会儿讲的时候,对吧?接下来呢,大家直接看它的这个资金码就可以了,我们这块呢,使用这个叫接拉lab,诶打开了对吧,直接呢我们来看一下这个叫T3。这个菜单里边这扣咱们一条条的来看这个指令。咱们呢,下边讲这个就是等我们讲完这个上篇以后呢,咱们中篇的时候呢,就给大家讲这个,呃,操作符,或者我们叫主机符是吧,它底层呢,所蕴含的这个资金码指令的这样情况,咱们现在的话呢,先直接使用一下,其实GVM的话呢,呃,很多同学呢,刚开始接手的时候觉得难学,嗯,为什么难学,难学到哪呢?我的体验是这样的,就是说你说我们先讲内存,先讲内存吧,里边又嵌到了,要想更好的去理解我们嵌到这个直解码是吧,那你嵌到这个直解码的话呢,我们要先讲直节码呢,这里边呢,大家也不知道内存,又不知道该如何的去理解这些。
02:16
这个这个资金码指令,也就是说呢,他们是相互之间嵌套着,我们特别难的去梳理出来一条路径,就是从零到一,一到二,二到三,这样的一个过程,互相嵌套着,想理解清楚它,需要懂它,呃,想懂它呢,又得需要懂点它,这样呢就是难到这儿了。嗯,是这样的一个情况,OK,行了,那咱们这块呢,来看一下,就是咱们这呢,是实用主义啊,就是这里边儿呢,我们用到什么,咱们就给大家讲什么。那在我们一开始的时候呢,这是一个A,这个A呢,就是咱们磁符串常量池里边一个A,然后呢叫哎二到一,这个呢,就是存放在我们叫局部变量表索引为一的这个位置,因为咱们知道呢,这个索引为零的位置呢,因为这个方法是非静态的,所以它呢,就放到了我们这个,诶放的是我们这个Z0的位置,放的是Z4,然后一的位置呢,放的是S1,对吧,然后意思呢,S2S3S意思往后放行,那我们再回去看这个代码,那把我们这个小A它的这个地址啊,就保存在我们这个本地变量表或叫局部变量表唯一的这个位置了,这是咱不用多说,前面已经讲过虚拟站对吧。
03:19
里边呢,S1就是在咱们这个战结构里边,这呢,哎,这是你这个T子三这个战帧是吧?战帧里边有个局部变量表是个数组嘛,然后呢,这个索引为零呢,是一个Z次缩引为一呢,是S1指向呢,就是我们在对空间里的字符串常量池里边的那个小A。大家脑子里边有这样的一个图景啊,我们说叫胸有成竹是吧,就是你画画竹子的时候呢,这个脑子里边已经有了这个竹子的一个全貌,那这呢也是一样,脑子里边你就想到这样一个场景就行了,那接下来的话,我们这个B呢,同样呢是来自于字符串常量池,然后呢,把它保存在啊,咱们对应的这个S2里边,S3的话呢,只是自串常量池里边一个AB,那取出来,然后放到我们这个S3,在我们局部变量表里边所因为三的一个位置,OK,下边呢,就是咱们要讲解的一个重点了,好,大家看,当我们通过S1加S2,就是如果你这个拼接或者叫连接符,左右两边只要是出现过变量。
04:13
我这呢是俩都是变量是吧,那你一个也是一样啊,只要呢,你出现过变量的话呢,这个细节是这样子的,我们呢,首先是new,一个叫string builder。因为一个build,然后呢,这个build咱们前面也讲过这个对象实例化的一个过程,对吧,咱们前面讲这个讲完这个这个方法去之后呢,咱们说过这个事,那这块呢是呃,其中的这个具体的几个环节嘛,嗯,那整整个来讲,这呢是调这构造器前面这个new的话,是我们开辟这个空间,包括有默认赋值等等这样一些环节啊,包括我们讲那个并化问题等等,对吧,行这呢相当于整体上构成了我们去new一个string build。一完这个build以后,你看下边呢,我们叫LO1。这个LOAD1啊,是从咱们这个局部变量表里边,把这个索引唯一的这个值呢,给它取出来,是不是就A呀,那取出来以后你干什么呢?我们调了一个叫呃喷的方法。
05:04
这个喷的方法呢,是咱们string builder里边这个方法,相当于呢,我们是调了openend的方法,把这个小A呢给它加进去了,然后呢,又调了一下我们这个索引V2上的这个就是B嘛,把它取出来,然后再是调一个喷,OK,那相当于咱们这里边咱们先这块呢写一下,嗯,有这样的几个细节。这个细节呢,咱们不妨就写到这吧。嗯,说这个,诶如下的这个S1加上这个S2咱就要加了,实际上这个连接操作在这个执行细节,细节什么样呢?首先第一步我们去new一个叫string builder没问题对吧,那new一个string builder,嗯,不妨这块呢,我就给他来一个声明吧。我就临时写了一个啊,这个人家没有具体的这个变量名了,这算是第一步,然后第二步的话呢,我们是。调了一下这个它的叫喷的方法,这个方法里喷的方法里边呢,把我们第无差常量值里边,准确的说呢,是我们从这个局部变量表里取的,当然局部变量表里面的是个地址啊,地址指向的又是常量池里表的A,把它把它呢做了一个open的操作,然后呢,接着这个三。
06:14
这个三的话呢,我们又通过它呢去调了一个喷,把这个B呢给它放进去。没问题,这是我们其中的两个操作,也就是说呢,我们这个S1加上S2呢,实际上呢,是我们嗯,通过两次喷的方法呢来实现的,然后在这我们来一个四,这个四的话呢,就涉及到我们现在需要的是一个字符串,而你现在给我的是一个string builder,那怎么办呀,咱们看到这里边掉了一个方法叫做to string。兔尊呢,相当于是我们返回的就是一个string build对应的一个字符串了,哎,直接S点兔。那这样操作就可以了,这个返回的就是一个string给的是它,那现在呢,我们关心的是不是就是,诶你这个兔子string里边是什么东西啊。是不是大家会有这样的一个疑问对吧?那么这个to string里边啊,咱们现在呢,先不展开来说,一会儿呢,咱们讲到这个intent的时候呢,咱们把它展开呢,给大家描述一下这个s.to string里边啊,我就先这样写啊,它呢类似于。
07:11
类似于什么呀,就是我们直接拗了一个string,这呢我放一个角黑,注意我这块这个词呢,用的还是非常严谨的,叫做类似于,有些呢,这个网上大家看一些帖子的时候呢,说啊不叫类似于,他说就等价于这个纽思润,其实不太是不太是一样的,大家这样来看啊,Ctrl shift t。啊,Build是吧,我们把build给它找到。第二,String build进来,好,CTRL,咱们看一下,这个叫to string方法就看这个呗。那to方法里边咱们呢,是当前这个string build这个对象我们叫to,大家看到是不是就是new了个string呢。就是纽,那为什么刚才我这块非要讲说类似于纽string呢,诶这呢涉及到问题,就是说我们这个new string啊,咱们讲in特的时候呢,给大家再讲一个非常常见面试题,想必很多人呢也都见过说new string到底底层呢造了几个对象。
08:05
招了几个对象,从这个层面来讲的话呢,跟就是我们这个操作跟咱们这个操作呢,是有一点区别的,但是现在呢,不影响咱们呃理解这个题的答案是吧,所以这块呢,我先写个类似于啊,具体细节呢,咱们呃通过讲那个下一节讲英特的时候呢,咱们看这里边具体的这个资金码,咱们就知道这个因为所以了。嗯,解决这道问题,暂时我们还不用研究这里边这个细节,好先到这儿,那既然你这块呢,Twoth three呢是new这个对象,那么咱们说new的这个对象的话呢,诶,或者我别说类似于了,咱说叫约等于吧,这样说类似于的话,好像说还不一样似的,约等于啊,那是这样的,那言IG呢,就是我们此时返回的是你这个是不是新造的这个对象的这个地址了。就是new string在堆空间,咱们说堆空间现在呢,有两个层面,一个呢是里边的字符串常量池,另外呢,就是你对象的这个区域,咱们这样来看,那咱们现在这个呢,相当于是不是你这个区域里边有个AB,然后呢,咱上边这个这个这个这个S3的话呢,相当于是在这个常量池里边有个AB,那显然呢,这两个是不是不是一个地址啊。
09:09
不是一个地址对吧,所以我们这呢,就是一个false。那明白这个意思行,那这呢我们多说一句,就是咱这呢叫S1加S2,但是这个string builder呢,咱们说底层用的是这个结构,这个结构的话呢,它是在咱们JDK5.0的时候,是不是新引入的一个API啊。那YG呢,就是我们5.0之前的时候怎么办呢。那我们5.0之前呢,咱们说用的呢,就是string buffer。用的是string buffer,所以它的执行细节目前呢是这样子的,那在这呢,我们稍微的补充一句。嗯,写到最后吧。补充就是在JDK5.0之后,嗯,使用的是string builder,这个呢,它毕竟是一个线程,不安全的,我们说执行效率呢是更高一些,对吧,那在GK5.0之前。
10:04
嗯,之前我们说,诶使用的是呢,叫string buffer。这个大家也没有必要再去跑到5.0之前呢去验证一下了,因为呢,咱们现在呢,用的API呢,也没有5.0之前的是吧,这个呢,你了解一下就可以了,诶我这呢也不演示了,行,那我们这呢,主要想说明的问题就是说当你这个符号左右两边呢出现过变量,那么它底层是如何处理的呢?就是去new string build,然后呢去openend openend,那这里边注意这个细节的,咱们这个变量呢,嗯,这个S是啊,这里边我定义的啊。定义的,其实呢,你也可以把它写成呢,是不是匿名的形式啊,就是new完以后呢,直接open open的这样的一个方式。是我这块临时定义的,人家那块底层可没说是叫SOK行,就是这么个事儿,那这个结果呢,咱们也很清楚了,那么这呢,我们想问一个问题,说呢,如果是这个拼接左右两边呢,是出现这种虽然叫变量名这样的形式,它就一定用的是string builder吗?
11:00
一定用的是builder吗?或者字符串拼接,这样用的是一定是build吗?显然不是的,像咱们前面呢讲的这种形式,这也叫拼接是吧?但这个拼接的底层肯定就不是build。那么如果都是这种像变量这样的方式呢,都是变量,那得看你这个变量这个变啊,咱们有时候得看你怎么说了,对吧,什么意思啊,就是你看我下边这个例子,真的自然而然我们就引出这个T4了,这个T4呢,跟咱们上面这个T3的区别在哪呢?就是我把S1S2呢前面加了final。我前面加了final了,加了final以后呢,你要从这看呢,这确实还是两个,这个咱们这时候你叫变量的话呢,这个变量就是指的是这个咱叫引用,应该说对吧,这应该叫引用了,这个引用其实它已经不是变量了,因为已经被final了,那么我们要问的问题就是说此时的S1拼接上一个S2,跟我们这个S3他们俩是一回事吗?跑一下。看到了这个结果呢,是不是就是触了,大家应该明白我这要说的意思了,就是我们这个左右两边,如果你要是变量的话呢,它就是拼接。
12:10
不是,它就是我们说用的这个随spring build对吧,但如果你左右两边呢,虽然是引用变,呃比较变量是引用,但是呢,它左右两边呢,不是变量,说白了还是这种常量的方式,那这个时候呢,它还是相当于呢,就给它合在一起了,那这呢是我们这个T4,大家来看一下,我们这个里边咱找一下这个T4,大家看是不是从我们这个idea呢,跟我们自动的一个反编译的角度看到还是一个AB对吧,这是一个场景,那另外的话呢,咱们也可以呢,还通过这个捷达lab,咱们看下这个四这里边这个code。然后大家呢,分析一下,看看前面呢,这咱们都说过了,三到四的时候,大家看咱们这个三呢,是从常量池里边取了一个AB,把这个地址呢,存储在我们这个局无变量表所因为三的位置就是给了S3了,然后你这个四的时候呢,你看还是在这个字符差常量池里边取得AB,把地址呢给了我们这个S,你看这显然是不是它俩是同一个地址啊。
13:03
那自然而然的,你这个等等的,它就是个出码。理解。理解对吧,OK,那这里边儿咱们想说明的这个问题呢,咱在这写一下。就是哎,字符串拼接操作,字符串拼接操作不一定。使用的是string build。嗯,不一定使用的是磁率标点啊,就是如果这个呃,拼接符号左右两边嗯都是字符串常量。啊或呢,就是我们说的这个叫呃,这个常量引用是吧,那我这块呢,想说的这意思,资料常量呢,就是说咱们直接这样写的这种方式。这是一种,那或者呢叫常量引用,常量引用呢,就指的是我们这样的方式,这个说呢,左右两边都是,就是且的关系啊则啊,这个仍然。
14:09
这个使用是不是叫编译器优化,编译期也可以啊优化,嗯,那就是非。嗯,非咱们这个,哎,String build的这个方式,OK,能理解对吧?这是我们说的这个场景,那从这个引申出来呢,咱们还想提到一个点,就是呃,Final咱们说是一个Java中的关键字,可以用来修饰呢,可以修饰类,对吧?可以用来修饰这个咱叫变量吧,嗯,或者叫基本数据类型,或者已经数据类型,对吧,还可以用来修饰方法,那修饰完以后的话,我们说这个类呢,就不能被继承了,方法呢就不能被重写了,这个所谓的变量呢,就不能是变量了,就得是个常量了,所以这块我们实际上还是想给大家呢去强调一个点,就是说如果咱们在这个开发当中能够用这个final的话呢,建议大家呢,就是使用上final。
15:02
哎,就是针对于final修饰,嗯,就是这个叫类方法,或者是这个,嗯,基本数据类型啊,引用数据类型。啊的,这个这个没法叫变量了。对吧,因为它这个修饰变量的就不是变量了,哈的这个量这样说吧,啊十是吧,就针对于final修饰这个结构的时候呢,大家呢,平时我们讲说能用的话呢,你就用上。啊,修饰这个量的这个结构时。那我们说呢,诶能使能使用上final呢,哎,就使用上。那时候还建议使用上。就是说我们这个类呢,其实本身你在整个项目当中,咱们呢,也没有给他去提供具体的子类,而且呢,也不准备给他提供,那其实呢,这时候你说我们发加不加呢,似乎呢,其实影响也不大对吧,那就是我们说建议呢,你就加上因为final修饰的这些结构啊,哎,它呢在这个实际上呢,大家如果看这个变量的话,咱们咱们还叫变量啊,就加引号的变量了,你去用final修饰一下,其实在它这个编译的时候呢,就把这个值呢,已经被确定下来了,咱们前面不是讲这个,说这个类的话呢,有这个看这。
16:18
有这个叫验证准备和一个呃,Result解析的过程,那在这个准备的时候呢,我们说针对静态变量呢,会进行一个默认值的一个初始化是吧,但是你要说加上final的话呢,它直接这块呢,就已经进行这种显示初始化了。就是它这个在复制的这个时期呢,要更早一些,OK就这样是吧,能加final呢,就建议大家呢,就加上行,这是我们说的这个问题,下边这个呢,相当于就是个练习题了。这个大量其实就都能会做,像我们这这就是常量,然后这种啊,这个呢是一个自常量,但是你这是个变量,那这样的话呢,它也是新旧的,所以这俩呢,它就是一个false啊理解行,那这块呢,因为我们加了个final了,所以它就是一个所谓的常量,那常量跟这个平移期,那S5其实就跟我们这S1呢是一样子的,所以它呢是一个处。
17:06
来保存一下泡泡。执行。嗯,没问题是吧,Fo处,好这呢咱们就过了,这个呢,说清楚了就知道咱们这个底层到底是一个什么情况。
我来说两句