各种中间件分布式高并发对答入流,但是一个String让面试官看透了她!!!

前言

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

环境

jdk1.8.0_171

win10家庭版

Talk is cheap , show me you code

//eg1

Strings1=newString("aa");

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

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

//eg2

Strings1=newString("aa")+newString("bb");

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

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

再来

//eg3

Strings1=newString("aa")+newString("bb");

Strings2="aabb";

System.out.println(s1==s2);//false

不叭叭,直接看图

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

//eg4

Strings2="aabb";

Strings1=newString("aa")+newString("bb");

System.out.println(s1==s2);//false

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

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

//eg5

Strings1=newString("aa")+newString("bb");

Strings2=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之后就是将堆中对象的引用复制一份放入常量池中。看图

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

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

再来再来

//eg6

Strings1="aabb";

Strings2=newString("aa")+newString("bb");

Strings3=s1.intern();

System.out.println(s1==s2);//false

System.out.println(s2==s3);//false

System.out.println(s1==s3);//true

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

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

//eg7

Strings1=newString("aa")+newString("bb");

Strings3=s1.intern();

Strings2="aabb";

System.out.println(s1==s2);//true

System.out.println(s2==s3);//true

System.out.println(s1==s3);//true

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了。但是你懂了吗?

//eg8

Strings1=newString("aa");//在堆中创建aa对象,常量池放入aa

Strings2="aa";//常量池中已经有aa了,所以直接把堆中地址拿过来就行

Strings3="bb";//常量池中放入bb

Strings4=s1+s2;//涉及到对象的相加,所以肯定是在堆中创建对象

Strings5=s2+s3;//涉及到引用相加,不能确定返回结果类型,所有是在堆中创建对象

Strings6="aa"+"bb";//常量相加,在常量池中直接放入

Strings7=newString("aabb");//堆中创建aabb对象,但是这个对象的并没有存aabb,而是存了一个指向常量池中aabb的地址值

Strings8="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);//

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

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

我可真会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

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

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

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

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343