String你真的会吗?不会还不进来!!!是等我胖虎锤各位呢?!!!

文章目录


前言

没啥子前言,就是之前写的一篇String笔记被别人夸了一下,然后发现自己写的有些地方是错了,所以好好整了一篇,还想体验一下被夸的滋味。

https://gitee.com/jjpp612/image01/raw/master/20200829/QZ@nILCJ7*ej.jpg

环境

jdk1.8.0_171

win10家庭版


Talk is cheap , show me you code


//eg1
String s1 = new String("aa");

先来看eg1,这一个最简单的创建String对象,老生常谈,这个过程创建了几个对象?这个问题主要点在于在常量池中有没有创建aa常量,不多叭叭,看图。

https://gitee.com/jjpp612/image01/raw/master/20200828/Ij2AsthjRRty.png

https://gitee.com/jjpp612/image01/raw/master/20200828/^a3mdnN3qZoK.png

Constant pool就是常量池,可以看到常量池中存在aa,也就是说eg1这个过程在堆中创建了一个对象实体,在常量池中也存了一份aa。s1指向的是堆中的对象实体。那么再来看一个。


//eg2
String s1 = new String("aa") + new String("bb");

https://gitee.com/jjpp612/image01/raw/master/20200828/K2phKy*d9L^s.png

嘿嘿,有意思了,常量池中只有aa和bb,new String(“aa”) + new String(“bb”)底层实际上是创建了一个StringBuilder,然后调用StringBuilder调用append拼接aa和bb,但是常量池并没有拼接之后的aabb,不是创建对象之前会先去常量池查找有没有对应的常量吗,如果没有就创建一个吗?为什么没有在常量池中创建aabb呢?突然想起来我师傅当时面试我的时候好像问过我,赶紧跑去问了一下,师傅给了我两拳,然后不紧不慢的打开浏览器输入了关键词。。。。。

https://gitee.com/jjpp612/image01/raw/master/20200829/Q6wD5b*7zNEa.png

经过一番激烈的百度,终于找到原因,原来是因为new String(“aa”) + new String(“bb”)是在运行期间才能确定类型的,所以不会放到常量池中。看图

https://gitee.com/jjpp612/image01/raw/master/20200828/GhtnEpVjZM8S.png


再来

//eg3
String s1 = new String("aa") + new String("bb");
String s2 = "aabb";
System.out.println(s1 == s2);//false

不叭叭,直接看图

https://gitee.com/jjpp612/image01/raw/master/20200828/fvB*PtI^d4pt.png

https://gitee.com/jjpp612/image01/raw/master/20200828/SnaTZDQrn5eB.png

虽然看反编译结果常量池中有aabb,但是那个aabb是s2 = "aabb"放进去的,s1还是指向堆中的对象实体。所以s1 != s2;


//eg4
String s2 = "aabb";
String s1 = new String("aa") + new String("bb");
System.out.println(s1 == s2);//false

这不是还是输出false吗?和pd3有什么不同,鹏鹏你是傻了吗?我知道在座的各位都理解了,但是我还是得把所有情况都实验一遍不是?谁让我是暖男呢?

https://gitee.com/jjpp612/image01/raw/master/20200829/kTRS3ak2FWDv.png

https://gitee.com/jjpp612/image01/raw/master/20200828/DBcCgCPONJ0E.png

https://gitee.com/jjpp612/image01/raw/master/20200830/SuoC9tcZuTUu.PNG

s1指向堆中的对象其实是没有创建char数组去存aabb的,直接存了一个地址值,这个地址值就是常量池中aabb的地址值。不用多说,各位人才肯定都懂的。那么继续喽!


//eg5
String s1 = new String("aa") + new String("bb");
String s2 = s1.intern();
System.out.println(s1 == s2);//true

先来说一小哈哈这个intern方法,来看看周志明前辈的深入理解Java虚拟机中怎么说的:

“运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只有编译期才能产生,也就是说,并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可以将新的常量放入池中,这种特性被开发人员利用得比较多的便是String类的intern()方法。”

想看这一部分的可以去深入理解Java虚拟机第三版的2.2.6章节查看。这本书真是太好了,简直是面试必看,哈哈哈。

我的理解:String的intern就是在运行期间检查常量池中是否有该字符串,如果有就直接返回常量池的中该常量的引用。如果常量池中没有,就得分版本了,在jdk1.7之前是直接将堆中的对象复制一份放入常量池;但是1.7之后就是将堆中对象的引用复制一份放入常量池中。看图

https://gitee.com/jjpp612/image01/raw/master/20200830/l^o4gyBhdOIQ.PNG

可以看到常量池中只有aa 和 bb,并没有aabb,所以常量池中只是存了aabb在堆中的地址值。

https://gitee.com/jjpp612/image01/raw/master/20200828/ol*^RensSBLh.png

s2的存的地址值和常量池中那个是一样的,都是指向堆中的aabb对象实体。所以s1 == s2;


再来再来

//eg6
String s1 = "aabb";
String s2 = new String("aa") + new String("bb");
String s3 = s1.intern();
System.out.println(s1 == s2);//false
System.out.println(s2 == s3);//false
System.out.println(s1 == s3);//true

https://gitee.com/jjpp612/image01/raw/master/20200830/X3NyB4o9PPaw.PNG

这儿常量池中aabb是s1 = "aabb"存进去的,s2=new String(“aa”) + new String(“bb”)只在常量池中存了"aa"和"bb"常量,在堆中存了"aabb"对象实体,s2指向的还是堆中"aabb"的对象实体,s3 = s1.intern()的时候,直接将常量池中aabb的地址值返回。所以s1 和 s3指向的都是常量池中的aabb,s2指向的是堆中的aabb对象实体。什么?还不理解,还不理解那就太好了,要不然我图不是白画了吗?

https://gitee.com/jjpp612/image01/raw/master/20200829/RxRiJNAuMq2*.png

[https://gitee.com/jjpp612/image01/raw/master/20200830/RISoYar8QI5^.png](https://gitee.com/jjpp612/image01/raw/master/20200830/DvuMURQYYi8M.PNG)


这下该懂了吧,什么?还不懂,那看下一个例子。

//eg7
        String s1 = new String("aa") + new String("bb");
        String s3 = s1.intern();
        String s2 = "aabb";
        System.out.println(s1 == s2);//true
        System.out.println(s2 == s3);//true
        System.out.println(s1 == s3);//true

https://gitee.com/jjpp612/image01/raw/master/20200830/HTkUDJ@LyCMl.PNG

https://gitee.com/jjpp612/image01/raw/master/20200829/Rb!hk*pH2cHA.png

s1 = new String(“aa”) + new String(“bb”)这一步操作在堆中创建了aabb对象实体,当常量池中并没有aabb,s3 = s1.intern()这一步操作是先去常量池中查找有没有aabb常量,发现没有,就将堆中aabb对象实体的地址复制一份放入常量池中(这是基于jdk1.7之后,我觉得jdk1.8之前的有时间可以去琢磨琢磨,没时间就别琢磨了,都出到jdk14了还琢磨那么古老的东西干嘛对吧,反正我用的一直都是1.8;之前琢磨jdk1.6也是被逼无奈,面一个初级java开发,人家都问我低耦合高并发各种锁的底层什么jdk1.8之前和之后有什么区别,我的老哥哥,我初来咋到你就想让我知道那么多,我还有时间写bug找你们帮我改吗?)


上面这几个例子都是基础,其他的面试题也是根据这几种情况改吧改吧出来的,要是上面这几个懂了,其他的也就是多思考一下就OK了。但是你懂了吗?

https://gitee.com/jjpp612/image01/raw/master/20200829/IYN3M!aLqqjv.png

//eg8
        String s1 = new String("aa");//在堆中创建aa对象,常量池放入aa
        String s2 = "aa";//常量池中已经有aa了,所以直接把堆中地址拿过来就行
        String s3 = "bb";//常量池中放入bb
        String s4 = s1 + s2;//涉及到对象的相加,所以肯定是在堆中创建对象
        String s5 = s2 + s3;//涉及到引用相加,不能确定返回结果类型,所有是在堆中创建对象
        String s6 = "aa" + "bb";//常量相加,在常量池中直接放入
        String s7 = new String("aabb");//堆中创建aabb对象,但是这个对象的并没有存aabb,而是存了一个指向常量池中aabb的地址值
        String s8 = "aabb";//常量池中已经有aabb了,所以直接将常量池地址值拿过来就好
        System.out.println(s1 == s2);//
        System.out.println(s4 == s5);//
        System.out.println(s5 == s6);//
        System.out.println(s4 == s7);//
        System.out.println(s5 == s7);//
        System.out.println(s6 == s7);//
        System.out.println(s4 == s8);//
        System.out.println(s5 == s8);//
        System.out.println(s6 == s8);//
        System.out.println(s7 == s8);//

各位人才可以把结果发到评论区哟!大家互相讨论,说不准就擦出了爱情的火花呢?

什么,你说连个妹子都没有怎么可能擦除爱情的火花?要我说,都单身那么多年了,你是不是该降低一下标准了?

https://gitee.com/jjpp612/image01/raw/master/20200830/IHHVq97Qr29d.PNG

我可真会yy,哈哈哈,想着自己写的文章能被很多人看见,你们是体会不到我现在的内心戏有多足,哈哈哈。

想来想去,我还是把答案写出来吧,别过两天我也不知道正确答案了,还得去运行一下。

System.out.println(s1 == s2);//false
System.out.println(s4 == s5);//false
System.out.println(s5 == s6);//false
System.out.println(s4 == s7);//false
System.out.println(s5 == s7);//false
System.out.println(s6 == s7);//false
System.out.println(s4 == s8);//false
System.out.println(s5 == s8);//false
System.out.println(s6 == s8);//true
System.out.println(s7 == s8);//false

上面每一步我也都注释了,不管对不对反正今天的我比昨天的我更强大了!!哈哈哈!!

https://gitee.com/jjpp612/image01/raw/master/20200828/acIUgm!xfz6Y.jpg

各位人才,各位大佬,有不对的地方各位请不吝指教!都看到这儿了,点赞收藏转发三连一下?祝各位早日找到女朋友。喜欢的朋友可以关注一下我的公众号敲代码的蛋蛋,一起成长,一起骚起来呀!!!

https://gitee.com/jjpp612/image01/raw/master/20200829/0SReFEOiO2.jpg

https://gitee.com/jjpp612/image01/raw/master/20200829/miD@ixe^Z!V9.jpg

我是Java鹏鹏,今天的你是否比昨天的你更优秀了呢?

tee.com/jjpp612/image01/raw/master/20200829/0SReFEOiO2.jpg)

[外链图片转存中…(img-FxxozwHD-1598801205517)]

我是Java鹏鹏,今天的你是否比昨天的你更优秀了呢?

参考资料 <深入理解Java虚拟机第三版>

  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值