00:00
那咱们刚才呢,已经说清楚了这个拼接操作啊,底层的具体的原理是什么了,右T呢,是我们这个拼接的时候呢,左边或右边当然也可以,两边呢出现的是变量的时候呢,底层是如何解释这样一个过程,行,那么关于这个细节的问题的话呢,我们可以再放到后边那个in里边呢,咱们再去谈一谈,就是针对于咱们上面不是说过一个叫约等于是吧,那这个约等于呢?诶怎么叫约等于,差到哪了?这个咱们到下边的时候呢,给大家讲,然后接下来咱们先做这样的一个测试,这个测试的话呢,我们是想看一看这两种情况的区别,差在差多少啊,一个呢,就是咱们通过一个for循环,然后呢,让我们这个字符串呢不断的去拼接。我们这这呢是设置了有10万次的执行,这是一种情况,另外一个的话呢,我们就造了一个string build,通过不断的去调这个openend的操作呢,我们实现数据的一个添加,看一下他们两个这个效率呢,到底差出来多少,注意你看我这里边没有明确说说他两个效率有没有区别,或者呢,他俩这个效率呢,就是会不会说差不太多,没有这样说,而直接呢,就说他们能差多少,因为呢,很显然我们说第二种方式呢,是不是执行的效率是要高一些的,对吧,那关键呢,就是我们说能差出来多少行,那咱呢,就直接先把这个麦一呢给它抛起来,循环呢,一共是有1万呃10万次。
01:14
执行一下。跑一下。看这呢10万次,按说次数呢也不少,看花花费的这个时间4014,嗯,执行出来了。4014好,然后呢,咱们把它呢注释掉,把下边这个呢打开,那针对于咱们这个麦二呢,也让它呢去循环10万次,看一下这样的一个情况。哎哟,这个速度呢,是不是快的有点吓人,七毫秒,那大家呢,可以相互呢,你去除一下,看一下这个倍数呢,是不是差距还是非常的明显的,对吧?那我们来解释一下,首先说呀,我们上边这个效率低呢,那是必然的了,为什么这么讲呢?咱们这里边儿你是有一个拼接,咱们意味着每次循环是不是都会创建一个string build。
02:01
每次循环都会创建一个string builder,而且呢,咱们也说了有一个to string方法,这个to string方法再去调用的时候,就是咱们在这个底层里边。底层呢,它会掉那个toth string,那掉to string的话呢,这里边又会去new一个string,所以这里边呢,咱们要具体说的话呢,每次不光去创建一个string builder,那而且呢,啊,这个我来个顿号吧,是不是还里边呢,会帮我们再去创建一个string呢,而这个string呢,就作为咱们返回的这个src的这个字符串了。所以这里边儿呢,创建对象其实呢,有10万个它是不是还对应着有10万个它了。没问题是吧,而我们下边这个呢,咱们就造了一个string builder,然后在里边呢,不断的去添加,自始至终咱们就只有一个string builder,那string都没有额外的再去创建。那显然的话呢,从创建对象这样一个角度来说,它进行的时间呢,是不是非常的多啊,OK,那咱们先把这个结论来说明一下,就是体会二者执行效率上来看的话呢,咱们这样来写啊,给大家建议一个多行的这个注释。
03:02
从执行效率来说呢,我们说这个呃,通过string这个builder啊,通过string builder的这叫append的这个方式添加字符串。啊的这个啊,判断的这个方式。添下字符串的这个效率啊,要是不是远高于咱们呢,使用啊这个string的啊,这个咱们叫X5串拼接方式对吧?这个呢是咱们相当于是通过这样一个测试呢,得出来这样一个结论啊,那得出这个结论的这个具体的好到哪儿,这个我们相当于是这个好处来分区分一下啊第一个呢,呃,情况我们要说明的是咱们自始至终啊,针对于这个这样的方式。嗯,在这说明一下这样的方式是吧,第一个自始至终。
04:02
嗯,是不是只创建过一个对象。创建过啊一个啊死针build的这个对象,嗯,这是这个情况,嗯,这个咱们。应该是这样来说,嗯,行,我就这样说吧,他呢自始至终只创建过一个对象,而对于我们这个,诶,String。字符串拼音的方式啊,要创建很多对象啊,这是关于我们具体的一个详情,应该是是吧。哎,创建过,哎这个。嗯,多个是吧,这个string build的对象和咱们底层调to string的时候呢,和这个string的对象,这个呢,是从我们说创建对象的这个角度呢,咱们来进行一个解释,那还有其他的角度吗?大家想还有其他角度吗?
05:01
你看我这写了一很显然呢,我们还有其他的想要给大家呢,去解释的点对吧,大家看咱们呢,这里边儿去创建了这个string。这个builder不断的去创建stream builder,那每创建一个新的话呢,我们下次再来的时候呢,也去造一个,诶造一个新的stream builder,把原有的内容给它加进来,那原来这个旧的builder是不是就不要了,而且呢,我们得到这个string的话呢,也同样的道理,那每次在创建新的时候呢,意味着我们旧的这个string builder或者string这个buffer,呃,或者这个string的话呢,就不再使用了,言外之意呢,就是我们在内存当中,首先呢,你是不是会创建过多的这string builder和string,导致呢内存空间占用过多,那其次的话呢,当然有可能你内存空间很大呢,咱们没有出现过JC,但是呢,你真正在去回收的时候呢,是不是要回收的这个,呃,Build对象或者SP的对象也更多一些是吧,所以第二个角度呢,就是内存中啊,这个由于。创建了啊,这个较多的啊,针对于我们这种方式。
06:01
啊,由于呢,创建了较多的这个string builder和string的这个对象啊,那么它呢,就是一方面呢,是内存占用了呢,啊,那同样的话呢,就是如果进行GC的话。哎,如何进行这个JC,是不是你也需要去花费额外的时间啊,诶这个呢,就是我们说这两种方式的一个区别,行,那通过这个呢,大家能够理解我们这个点就可以了,行,那么这呢,咱们还想再给大家多说一句,就是咱们这种方式呢,虽然好,那这种方式呢,还有有没有这个改进的空间呢。是吧,哎,那还有没有改进的空间呢?实际上也有啊,这里我们再说一下啊,这个改进的空间。嗯,那改进的空间在哪呢?大家注意,咱们此时呢,使用的是string build的一个空餐的构造器。啊空难过去,那我们这块改进空间呢,并不是说把这个string builder呢,改成string buffer是吧?那显然不对,那string buffer呢,是同步的,这个效率反而更差一些,那我们想说的是呢,这个string build呢,你看咱们底层默认的情况下呢,掉了这个修复,修复这里边呢,那这个值呢是16,相当于咱们一开始创建了一个底层长度为16的一个数组,叉形数组,然后呢,咱们将这个那要添加的这个字符串呢,是不断的添加到咱们底层的这个叫叉形数组当中,那当不够的时候怎么办呢?是不是自然而然的要进行一个扩容操作呀。
07:26
也就是说呢,咱们在调用这个pen的时候呢,又调这个super的这个操作,然后在这呢,需要确认一下,你当前要添加这个字符串进来以后呢,这个容量是不是够啊,容量呢要不够怎么办呢?你看这里边我们需要呢做一个扩容,这叫copy是吧,New capacity这呢,我们就看到扩容的一个比例。那你扩容完以后,是不是还需要将原有的这个字符串中的数据呢,再copy到你这个新的这个数组当中啊,能理解对吧?那就意味着一开始我们长度是16,然后后边呢就需要扩容,那后边呢,可能再有扩容,那如果说咱们现在是不是有10万个数据需要添加,那这里边显然呢,是不是要扩容过多次啊。
08:01
那你一旦扩容一个新的之后呢,旧的呢肯定就不要了,这呢又涉及到内存中占用空间呢,可能比较大一些,那能不能说一次扩这个就建一个长度比较大的一个数组呢?那其实呢也是可以的,这就是我们优化的一个点,在咱们这个string build当中,它呢还有一个专门的一个构造器,咱们看一下。那就是我们这个build的。嗯,这个是吧,这呢它有个参数呢叫capacity,这个capacity呢,就影响到我们底层创建这个查询数组的一个容量。所以呢,在我们这个实际开发当中啊,咱们改进的空间是什么呢?就是在啊实际啊这个开发中说啊,如果基本确定这个要啊这个前前后后。啊,添加的字符串长度呢,还不高于某个线定值。限定值的这个情况下啊,这个比如不高于某个限定值,这个我们来一个比如叫high吧。
09:04
不高,不高于某个限定值high level的,这个情况下呢说建议使用构造器。哎,这个构造器呢,就是我们下边说的这个,咱们呢是string,嗯,Puder啊这个有一个int型的啊,或者这块我就直接建议这样呢去创建对象了哈,New一个S这呢就直接放我们这个叫哎嗨,Level。嗯,这个呢,就意味着我们底层呢,去扭了一个插型数组,这个插件数组它的长度呢,就是这个叫high level。因为呢,你不会超过这个值,所以呢,咱们就尽量避免呢,底层不断的去扩容这样的一个事实,那同样呢,它还可以呢,去优化我们这个程序的一个执行效果是吧,诶建议。使用如下的构造器实体化。OK啊,这呢就是我们通过这样的一个说明来这个对我们开发中进行的一个启示,行这个呢大家应该能够清楚是吧,好,这呢就是我们要强调这个点。
我来说两句