00:02
好,S1等于它,S2等于什么呢?我们这个字符串实际上会从这儿拿过来,用的是同一个对象啊,加上它,哎,这是这是两个吧,一个对象两个对象,这两个拼完之后是不是三个对象啊,所以这两行代码一共是创建了三个对象啊。创建了三个字符串对象呢,那么这个呢。这个在这实际上是XY在上面已经创建好了,对吧,XY在字符串常量池里边,你new一个string,只不过这是个新的对象,在堆里边多了一个对象。啊,New钝new对象的时候,一定在堆内存中开辟空间的。啊,他是这样做的,各位啊,行,那第一个例子,我最主要是想也没什么实质性的代码,想跟大家聊一聊,字符串一旦创建用双引号括起来,这在字符串常量池里边,一旦创建不可变,一旦创建不可变啊各位。然后呢,还有一件事就是什么事,就是new string的话,它是在堆里边开辟空间的啊,然后呢,这个堆里边开辟空间啊,保存内存地址怎么着啊,指向这个对象啊。
01:07
来这个文件我们保存一下,保存这个是D25 D25,然后接下来我们写上去啊,叫做string的内存图。好,这个我就关掉了啊,来继续。啊,继续看啊,我在这儿呢,有一个class,各位这个class我叫user,这个user啊。我给他一些属性,比如说有ID,比如说有string name,然后加上去构造方法,无参的来,我们再加一个什么呀,有参数的构造方法。有参数的啊,构造来,我们再加上set get方法,Set和get方法来,这个没什么可说的啊,普通加油类,然后在这呢,我们加一个类,这个类呢叫user test,然后这个user test PS vm,接下来user user啊,User new一个什么呀,User new的时候呢,这块呢,我是这样做各位啊。
02:09
嗯。我现在应该怎么做啊?嗯。这个位置呢,传一个110吧。Name传一个张三,这个内存图该怎么画个?就是这是一个U的这样的类,这个类呢有一个有参数的构造方法,这里呢,去调了一下这个110和这个张三就通过参数传递的方式传给了这个,呃,这个属性和这个属性是吧?那如果现在是这样的代码的话,它的内存图会是怎样的?我觉得这个也有有必要再重新画一下,跟以前可能就不一样了,各位啊,跟以前就不一样了,来这块呢,线条让它变得细一些,来这边写上这个是GM,然后再来啊,大家注意看啊,整个这个呢,我们叫什么叫做方法区。是吧,这是肯定的,没没什么可说的,方法区方法区啊,然后接下来这边呢,就是我们的一个堆了堆啊,然后在这写上这叫堆,哎,然后接下来我们这块呢,该有占还是有占啊来有占来这个呢是我们的一个占空间啊,然后接下来我们同样呢,还是老规矩,把这儿呢给它截掉了,不要了啊好了,那么接下来咱们看看这个程序,首先第一个我们会进行类加载,它呢加载进去它呢加载进去它呢加载进去是不是?哎,会进行类加载,所以这块的代码呢,应该是我们的一个叫做user test.class然后顿点class user.class是不是,哎,然后呢,这是一个代码片段啊,还有一个静态变量等等等等等等,是不是在这存啊,然后接下来这里面有个字符串常量池啊,这个字符串常量池,你去理解一下。
03:50
啊,在这里边儿有这么一个常量池啊,常量池,那么这个常量池首先呢,我们先执行焖方法,焖方法一定会压站,所以在这块的话,我们有一个叫做men方法战争啊来写上去我们的men。
04:03
方法占针好,接下来我们应该是先拗是不是?哎,那么拗的话,这块是不是就在堆里边会多一个对象啊。那么在哪儿会多一个对象?会在这个位置多一个优对象?注意啊,这里会多一个user类型对象,User对象。啊,U的对象,然后接下来呢,我们U对象里边有一个属性,各位什么属性,因为你在这里把110传给了我们的这个ID,这个ID又给了这个ID,这个ID是个int类型,基本数据类型,所以它应该是在这里有一个什么呀?哎,有一个空间,有一个空间啊,这个空间里边它是什么呢?它属于一个int类型的ID,它里边存的是多少啊,110啊,一百一十幺幺零啊,那紧接着呢,你这个程序啊,再往下走大家看。见到双引号,这个双引号里边的东西一定会在哪建一份,各位一定会在字符串常量池里边会多一份,这是是不是我上一个例子给大家讲过的,在这里是不是一定会多一个字符串对象,而这个字符串对象是不是就叫张三?
05:05
对吧?哎,这个对象有没有,这是死string对象啊,这就是死string对象,各位死string对象啊,不可变啊,不可变,双引号括起来东西不可变,在字符串传池里先有一份,因为建双引号就有一份,各位啊,你只要在程序里面建双引号就有一份,好,这个有了之后,接下来他把它付给了谁,把它把这个传过来付给他,他呢,又付给谁呀?付给这个name,而这个name谁是他呀?对吧,哎,它那么这个时候呢,其实就相当于在这里啊,它有一个什么呀,哎,有一个。String name啊,注意听啊,这有个string什么name,那么这个string name里边保存的是什么呢?是这个张三在字块里边这个对象,它的内存地址。它的对象内存地址实际上在这个里边,它是什么呢?0X111,这个0X11就指向谁呢?是指向它的。啊,以前你还记不记得杜老师在画的时候怎么画的呀?哎,没给大家说这个字符串常量池,也没有说这个东西的时候直接是不是将是不是在这就咔放一个张三过来,实际上这个图不太对。
06:07
不太对啊,String name这个name变量里边,Name变量当中,记住啊,这个变量里边它存的不是字符串。明白吗?这个变量里面存的是地址,是一个字符块对象的地址。尴尬了吧?哎,ID里边人家存的是110,你因为name是个引用啊,你string不是个类吗?你既然是类,那你就不能特殊化,你说name里边保存的是张三,不对啊,Name里面实际上是保存张三这个对象,它的内存地址,张三是个字符串对象。啊,自不出对象是这样一个情况,当你整个这个user对象创建完之后,接下来你是不是把它付给了一个局部变量user user啊是不是,那么这个时候就相当于在这个位置上有什么user user,然后呢,接下来哎,它应该有什么呀?哎,一个地址,而这个地址呢,就是我们堆内存当中这个对象呢,地址啊0X1231241247啊它呢,去指向谁呢?它去指向了,哎我们对应内存当中的这个user对象啊实际上是这样一个情况,各位啊,这样一个情况。
07:05
是这样的啊,是这样的,注意我再强调一下啊,主要强一件事就是STRINGS1等于ABC1里面保存的不是ABC字符串啊,是S1里面保存的是。ABC字符串对象的内存地址,你要知道这件事。就主要是想说这件事,各位啊,来,我把这个呢加粗一下,然后它标成红色啊,标示重点啊一的ABC实际里面保存不是ABC,字符串是ABC,它在字符串常量池里边,然后这个常量池这个对象内存地址怎么着?哎,付给了我们这个SE,这个引用SSE里边实际上保存是内存地址。是个内存地址啊,S1当中保存是内存地址,来保存一下啊,来我们给大家写上去,这叫DAY25啊,我们就来string类型的引用中,同样也是保存了对象的内存地址。
08:09
是一个道理啊,一个道理。好,这个呢,我就先关掉了,各位啊,先关掉了来,那么这块咱们继续再往下。在这里呢,我们。继续啊,在这里呢,我们来一个class,我们叫TEST02走,那么PSVM啊。这样大家注意看啊,转S1等于哈,然后死转S2等于哈,好,我问大家一个问题,S1等于等于S2,这个结果是true还是false,大家分析一下。分析啊,分析结果是true还是false?
09:02
好。这个结果是true还是false?那么同样我们得也得画图,各位啊,画一下图。来别着急啊,咱们慢慢来这个东西啊,咱慢慢去学啊,画图可以说明一切问题啊,这就是杜老师的一个风格啊,不画图说不明白,画个图咱们就能说明白了啊,咱们把一切的东西都放到图上啊,来这个地方还是方法区,来这就比较慢一些,是不是慢一些,慢一些吧,咱们大家都能学会,我觉得这是最主要的,出去之后咱们怎么着也得像个两年两年的程序员是不是啊,工资咱们高点啊,这样的话咱们做的会好一些啊,来我们这块的话,我们把它删了啊,删了之后呢,呃,先保存一下吧,保存一下啊啊对,25啊,就是string相关面试题啊,就这一块的话,它怎么做的呢?首先呢,它会进行一个什么呀,我们的一个类的一个加载,这个类呢,还有这个类是不是都会装载进来,那这样的话在这呢,我们就是一个叫做点class,还有这个点class是不是好了,那这样的话我们,嗯在这呢,有什么呀,静态变量啊。
10:18
啊,代码片段呀,等等等等吧,哎,还有叫字符串常量池是不是,那么这个字符串常量池里面目前是没有东西的啊,然后接下来我们这块呀,是怎么做呢?是S1等于hello。是不是啊,哎,等于hello啊那哈,它这个是不是会在我们的这个方法区里边会先有一份啊。对吧,哎,先有一份啊,那有一份,这就是那个字符串对象词string对象啊,String对象,然后接下来这个string对象付给了谁呢?付给了我们那个啊,我们这个程序里边的SSE,这个SSE在闷方法当中是一个局部变量,所以在我们的闷方法里边有一个闷,诶有一个站里,站里边有个闷方法战争啊来写上这叫闷方法啊站真好了,那么这个时候呢,我们在这儿呀中的S1,然后接下来我们把这个。
11:08
画出来啊,这个S1这个变量指的就是它,它呢里边保存了一个地址,这个地址是0X1111啊,然后去指向了谁呢?哎,我们的这个常量池当中的这个,哎,字符串对象。那么接下来呢,我们紧接着呢,我们死顿S2又等于双引号哈,那双引号hello,由于它是存储在什么,哎,Hello,双引号哈是存储在方法区的字符串常量池当中,所以这个hello不会新建啊,不会新建,各位直接拿来用就行了。啊,因为这个对象已经存在了,因为这个对象已经存在了。明白吧,所以这个时候呢,S2它同样啊,在这怎么做的呀,他这样做的。
12:03
String SR这个SR里面保存了,哎,这是个变量啊。保存了一个什么呀,地址。对不对,哎这个地址是什么呀,也是多少啊,叫做0X什么111111啊,1111,哎,然后它呢,同样也去指向了什么,哎这个对象。啊,这个对象,那大家思考一下,现在的这个S1这个变量里边保存的这个东东和S2这个变量里边保的这个东东一样不一样,双等号比较的是不是内存地址啊。还记得吗?双等号比较是不是不是变量里边内存地址啊。双等号比较的是不是?变量中保存的内存地址。答案是的,双等号比较的是不是变量中保存内存地址,对呀,那你这个hello和这个哈,都在这个常量池里面对不对?所以我问大家这个程序最后的结果是不是就是处啊。
13:09
是不是啊?对吧,因为你这个和这个一样啊,都指向常量池里边这个啊,所以这个结果就是true啊没问题啊没问题。啊,没问题,来我们看一下。对吧?哎,结果是true,没问题啊,没有任何问题,那么接下来又来了string X等于new,一个string,然后接下来写上一个XYZ,然后再来一个string y等于new一个string,然后接下来再写一个什么呀,XYZ,那么这个时候我们CX等于等于Y,现在这个结果是true还是false?来分析一下分析啊,分析结果是true还是false?那如果你的程序是这样做的话,就相当于说你一个string,这是XY双引号是吧,XYZ这个双引号。
14:01
这个双引号它一定会在这里多一份,这是百分百没跑了,对吧,因为这个叫字符串常量池。字符串常量池不会被垃圾回收器回收,各位啊,字符串提一下啊,提一下垃圾回收器不会不会回收常量的,常量这个东西一旦创建不会回收的啊,不会回收的。垃圾回收器是不会释放常量的。是不会释放常量池里东西的啊,突然就想起来这么一个事儿,给大家说一下。这个啊。然后接下来呢,我们这个程序啊,XY这个对象有了之后呢,就相当于这不双引号吗?建双引号就有对象吗?好,这个对象new一个string,那你new一个string,它会导致堆里边会多一个对象。对吧,这就是那个string对象啊,这个string对象它里边啊,它保存的是什么?是我们这个XYZ,它的一个内存地址,它的这个内存地址,各位啊,内存地址我写上去,比如说是0X2589,然后这个0X2589指向谁呢?指向了我们的哎,这个XYZ。
15:15
明白,哎,指向XYZ啊,指向XYZ,那么我们现在呢,这个string有了之后呢,这个string,接下来这个对象创建出来,这个内存地址付给了谁呢?付给这个string X。而这个string X是谁呢?哎,是我们在。这不够不够了是吧,不够了。不过往下拖一下。行吧,往下推一下啊,有办法你看。是不是啊,有办法啊,是这回事儿就行了,来这个也是一样。这个一样的。好了,那么这块呢,它会有一个什么呀,叫做哎,String X,而这个string X呢,它也是一个什么呀,哎,一个变量。
16:03
这个X指向谁呢?指向这。然后接下来这个X里边保存这个内存地址是什么呢?是这个0X4444,那这个0X4444指向谁呢?指向的是我们这个存对象。啊,这个对象各位。因为你拗了呀。是不是,那接下来呢,你这个程序又去new一个string X y z,由于这个XYZ怎么着,在我们常量池里面已经有了,所以这个就不用创建的,New一个string还是要创建的,因为你nu一次,它一定会在堆里边会多一个对象。会在这个位置上再去创建一个什么呀,叫做string对象。啊,这是顿啊,那么这个string对象里边同样保存的也是什么呀,叫做0X什么呀,2589 2589啊,而这个2589呢,去指向指向了我们这个XYZ啊,指向XYZ,但是你这个对象毕竟已经创建出来,它也有内存地址给了谁给了我们前面这个局部变量叫string s string y。
17:03
那么这个时候呢,我们这儿呢,应该是有个死中用Y的死重用Y呢,这块呢,有一个地址对吧?哎,这个地址我就直接写了,各位啊,等于什么呀?哎,等于。一个新的呗,对吧,等于0X2222。对不对,哎,而这个0X222去指向谁的,指向我们这个对象。指向我们这个对象的各位啊。那么我们双等号判断的是什么?X和Y,大家看看双等号判断的是不是对象的这个变量里边保存的内存地址啊,对吧?哎,注意这里啊,还是那句话,双等号比较的是不是变量中保存的地址?答案是的,那么这个时候X这个变量里边保存的是一个对象的内存地址,Y里边保存的是另外一个对象的内存地址,所以这个结果是不是就是false啊,所以我们去执行一下。好,一个是true,一个是false,好,同学们通过这个得出一个什么结论,字符串的比较不能用双等号对吧?
18:03
是不是通过这个案例的学习,我们知道了字符串对象之间的比较不能使用双等号,双等号不保险明白吗?双等号不保险听懂了吗?哎,应该调用死类的什么equals方法。好,反过来又来了,各位又来了,我问大家equals方法是不是object这个类里边的。Object这个类当中是不是有一个equals方法,各位这个equals方法是不是用的双等号?所以我问大家,这个equals是不是也不能用?对吧?那么死类有没有重写equals方法呀?这个它的ES是不是比用的双等号。
19:02
对不对,所以这块你看看string string这个类叫java.string。对吧,找到string这个类之后,我们来找一下这个类当中的equals。找一下啊,我们的一个equals方法,那这就是equals你看。对吧,这个ES方法是不是非常显然他已经怎么着了,重写了吧。是不是重写了?重写了各位啊,他重写了,所以在这里呢,你要比较字符串相等不相等,X点1COS y。听懂了吗?你应该用这种方式,那你用这种方式的话,它的结果是不是就是true啊。这个ES是不是XX是不是字符串,字符串的equals方法吧,来走一个。好,大家看是不是最后一个就是我们看一下啊,你看。对吧,所以通过杜老师的讲解,我不知道大家有没有去理解,有没有去理解我们这个这个这个程序啊,这个程序就是说我们的字符串比较不能用双等号,用等号就不对了。
20:07
因为这XY这个这个XY是一样的,X和Y是应该是同一个表示同一个字符串,所以E口方返回应该是true。啊,所以在这里呢,我们也知道已经重写了equals啊顿类,此顿类呢,已经重写了方法,以下的equals方法调用的是。是什么呀,是string重写之后的S啊,重写之后的S方法,明白这个方法是我们类重写之后的,所以可以。那刚这这个之前啊,有一个同学问了一下,我说老师我这个代码不看不太懂什么意思,比如string类型的K吧,New一个string啊,现在我在这有一个字符串啊,或者是这个这个字符串啊。我写上啊叫什么叫做test啊,String,然后接下来我在这呢,写了一个什么呀,叫test string.equals k好,各位这个代码能看懂吗?为什么双引号字符串可以去点啊。
21:07
哎,为什么双引号。就为什么test string这个字符串可以后面。加点呢。诶。因为双引号太子的顿是一个string对象。只要是对象都能调用什么呀方法。明白吗?而且这种双引号括起来,字符串放到前边的话,你这个有两种写法,一个是字符串放前面,一个是k e cos谁啊,它这两种方式都行,但是建议使用这种方式,建议使用这种方式啊,因为这个可以避免空指针异常。
22:17
对吧,哎,你注释掉,假如说K现在是空,我问大家哪个有问题,是不是这个结果是false,因为K是空嘛。前面这个不相等,所以这个是不是false,但是执行到第29行,我问大家是不是就一定是。空的引用去调E是不是出现空指针异常啊,走那一个是false对吧,一个是空指针异常,所以这个代码它存在空指针异常的风险。明白吧,是存在什么呀,空指针异常的风险,不建议这样写,建议这样写,听懂了吗?哎,当然你如果不是一个空的话,这两个没有区别,这个是for,这个是,呃,这个true,这个是,哎处吧,来走一个。
23:13
这样。稍等片刻啊,来看一看结果,好,True和true是不是?哎,没有任何问题。
我来说两句