剖析new String()创建几个对象?及不同的方式创建的string对象有什么区别?
创始人
2025-06-01 13:57:11
0

今天看到一个很有意思的高频面试题,其中的内容确确实实很有意思,下面我们来聊聊,先来看几道面试题,试试水平;

目录

面试题类型1:

面试题类型2:

 解释:

目前来看,关于 new String("xxx") 创建对象个数的答案有 3 种:

  首先回顾「字符串常量池」:

下面我们看看JVM是如何处理面试题类型一中的前两个代码的:

新知识引入:

使用+拼接字符串的实现原理


面试题类型1:

分别执行下面代码:请回答执行他们的过程中总共创建了几个字符串对象?

代码一:new String("xxx");//一个或两个

代码二:String str = "abc" + "def";//0个或一个

代码三:String s=new String(“xxx”);//一个或两个

代码四:String str = "abc" + new String("xxx");//5个

面试题类型2:

回答如果执行下列代码,分别返回的结果都是什么?

String s1 = "Java";
String s2 = "Java";
System.out.println(s1 == s2);//true
String s1 = "abc";
String s2 = new String("abc");
System.out.println(s==s1);//false
String s1 = new String("javaer-wang");
String s2 = new String("javaer-wang");
System.out.println(s1 == s2);//false
String s1 = "abc";
String s2 = new String("def");
String s3 = s1 + s2;
String s4 = "abcdef";
System.out.println(s3==s4); //false

 解释:

接下来我们一边解释面试题,一边总结相关知识点;

目前来看,关于 new String("xxx") 创建对象个数的答案有 3 种:

  1. 有人说创建了 1 个对象;
  2. 有人说创建了 2 个对象;
  3. 有人说创建了 1 个或 2 个对象。

而出现多个答案的关键争议点在 【字符串常量池 】上,有的说 new 字符串的方式会在常量池创建一个字符串对象,有人说 new 字符串的时候并不会去字符串常量池创建对象,而是在调用 intern() 方法时,才会去字符串常量池检测并创建字符串,那么实际情况是怎样的呢?我们接下来慢慢聊。。。。

  首先回顾「字符串常量池」:

  • 字符串的分配和其他的对象分配一样,需要耗费高昂的时间和空间为代价,如果需要大量频繁的创建字符串,会极大程度地影响程序的性能,因此 JVM 为了提高性能和减少内存开销引入了字符串常量池(Constant Pool Table)的概念。
  • 字符串常量池相当于给字符串开辟一个常量池空间类似于缓存区,对于直接赋值的字符串(String s="xxx")来说,在每次创建字符串时优先使用已经存在字符串常量池的字符串,如果字符串常量池没有相关的字符串,会先在字符串常量池中创建该字符串,然后将引用地址返回变量,如下图:


下面我们看看JVM是如何处理面试题类型一中的前两个代码的:

JVM如何执行String s="abc";
        JVM在执行String s="abc"时,会先在常量池中查找是否存在"abc"这个字符串,如果存在,则将s1指向该字符串;如果不存在,则在常量池中创建一个新的字符串"abc",然后将s指向该字符串。如果在后续的代码中使用了相同的字符串字面量,JVM会重用之前创建的String对象,而不是创建新的对象。

JVM如何执行new String("abc");
        当执行 new String("abc") 时,JVM 会首先在常量池中查找是否已经存在 "abc" 这个字符串,如果存在,则直接返回该字符串的引用;如果不存在,则在堆中创建一个新的 String 对象,并将 "abc" 这个字符串的引用赋值给该对象。同时,该对象会被添加到常量池中,以便下次使用时直接返回该对象的引用。

        你也可以这样理解;new String("abc")相当于new String(String s1="abc"),即先要执行String s1="abc",然后再在堆区new一个String对象。

因此,现在可以解答本文的标题了,String s=new String("abc")创建了1或2个对象,String s="abc"创建了0或1个对象。

我在博客上看到一位博主对以上执行过程分析为:

String s="abc"会先从字符串常量池(下文简称常量池)中查找,如果常量池中已经存在"abc",而"abc"必定指向堆区的某个String对象,那么直接将s指向这个String对象即可;

我并不认可这句话(仅仅代表我的观点),下面我们用例子来证明我的观点; 

按照以上说法;下列代码返回的值应该为true,我们实际执行看结果;

String s2="abc";
String s1=new String("abc");
String s3=new String("abc");
System.out.println(s1==s2);//false
System.out.println(s1==s3);//false

 我们再次通过一个例子更加贴切的理解一下该过程(我们在看一个例子):

底层原理图与原理我们用画图来解释;

 

 String类型的数据都存放在常量池,堆中的属性只存放常量池中值的地址!

①    String str1 = "abc";语句是直接创建了字符串,是构造字符串最常用的方式。这种直接赋值的方式,并没有用new关键字在堆中开辟新的地址,而是在常量池中开辟了地址。所以引用str1的内容是常量池中abc字符串的地址0x01。

②   String str2 = "abc";也是直接创建了字符串。但是因为String是特殊的引用类型,其存放在常量池的内容是不可变的。在创建一个字符串对象时,会先在常量池中查询是否已存在,若不存在则再开辟新的存储空间。此时str2所引用的对象abc和str1是一样的,所以这是常量池中已经存在的内容。Str2会直接引用常量池中这个已经存在的字符串对象。所以str2的内容也是常量池中abc字符串的地址0x01。

③    String str3 = new String("abc");语句用new在堆中开辟了空间,是通过创建对象来创建字符串的。str3指向堆中一个新的空间的地址0x02,此空间中存放String对象的属性值。同样的,此属性值在赋值为"abc"时,会先在常量池中查询是否已存在此内容。此时常量池中已经存在了abc,所以属性值存储的是常量池中abc的地址0x01。

④    String str4 = new String("abc");语句也是用nuw在堆中开辟了空间,利用创建新对象来创建字符串。str4指向堆中一个新的空间的地址0x03,此空间中存放String对象的属性值。同样的,此属性值在赋值为"abc"时,会先在常量池中查询是否已存在此内容。此时常量池中已经存在了abc,所以属性值存储的是常量池中abc的地址0x01。

⑤    如果通过创建新的对象来创建字符串,发现常量池中没有已存在的字符串;那么JVM会继续在常量池中开辟一个新的空间并把值存放在其中,而堆中的属性值为此空间的地址。

以上案例来源:https://www.baidu.com/link?url=xlIOX3u9Gv11cc6XlDpWjEIMaDrhaWtKinWiDEle_GNNz-OVvqntCjlr2o9FDVbj&wd=&eqid=a5c4a04300005cce00000003641ad2c6


然后我们来解释一下一下代码:

代码二:String str = "abc" + "def";//0个或一个

代码四:String str = "abc" + new String("xxx");//5个

        对于代码二中,如果你不知道他的底层实现,你估计会首先想到String str = "abc" + "def"执行过程中首先创建了两个对象“abc”和“def”然后在进行拼接最后构成第三个对象str;然而实际并不是这样,对于我们的JVM频繁的创建对象是很浪费内存和时间的,那么JVM是如何处理使用“+”进行的字符串拼接的呢?

        底层实现:用+操作符拼接字符串,会产生一个中间对象,如果是线程安全的环境,我们会用StringBuffer拼接字符串,线程不安全的环境则使用StringBuilder。

        总结:上面的问题涉及到字符串常量重载“+”的问题,当一个字符串由多个字符串常量拼接成一个字符串时,它自己也肯定是字符串常量。字符串常量的“+”号连接Java虚拟机会在程序编译期将其优化为连接后的值。就上面的示例而言,在编译时已经被合并成“abcdef”字符串,因此,只会创建1个对象(你也可以说是两个,因为还可以加上stringbuffer或stringbuilder)。并没有创建临时字符串对象abc和def,这样减轻了垃圾收集器的压力 ;

引入一个知识点:

        JVM在编译我们自己写的代码时,会将我们写的代码进行优化      

理解了上述例子,那么第四个例子也就好理解了:

        上述的代码Java虚拟机在编译的时候同样会优化,会创建一个StringBuilder来进行字符串的拼接,实际效果类似:

String s = new String("def");
new StringBuilder().append("abc").append(s).toString();

很显然,多出了一个StringBuilder对象,那就应该是5个对象。

        此时,你也或许有这样的疑问,StringBuilder最后toString()之后的“abcdef”难道不在常量池存一份吗?这个还真没有存,我们来看一下这段代码:

    String s1 = "abc";String s2 = new String("def");String s3 = s1 + s2;String s4 = "abcdef";System.out.println(s3==s4); // false

        按照上面的分析,如果s1+s2的结果在常量池中存了一份,那么s3中的value引用应该和s4中value的引用是一样的才对。但是结果却大相径庭,他并没有存到常量池中而是存到了堆内存中,上述代码会证明此观点;

为什么会这样呢?我们记以下概念:

仅有使用引号包含文本的方式创建的string对象之间使用“+”连接的新对象才会被加入到字符串常量池中,而对于包含new string()或null“+”字符串的连接方式产生的新对象不会被添加到字符串常量池中;

验证上述概念:

        /*String s5="qwe"+"asd";String s6="qweasd";System.out.println(s5==s6);//true*/String s5="qwe"+new String("asd");String s6="qweasd";System.out.println(s5==s6);//false

继续总结:

String的两种初始化形式是有本质区别的。

String str1 = "abc";  // 在常量池中

String str2 = new String("abc"); // 在堆上

新知识引入:

使用+拼接字符串的实现原理

        前面提到过,使用+拼接字符串,其实只是Java提供的一个语法糖,看看他的内部原理到底是如何实现的。还是这样一段代码。我们把他生成的字节码进行反编译,看看结果。

String a = "Hello";
String b = "world";
String c = a + "," + b;

反编译后的内容如下:

String a = "Hello";
String b = "world";
String c = (new StringBuilder()).append(a).append(",").append(b).toString();

        通过查看反编译以后的代码,我们可以发现,原来字符串常量在拼接过程中,是将String转成了StringBuilder后,使用其append方法进行处理的。也就是说 +和StringBuilder的append等价,

也就是说使用+拼接字符串的实现原理就是使用StringBuilder.append。

其实偶尔看看Java知识点的底层实现也是很有意思的,希望大家在学习中能够拥有刨根问底的学习精神; 

我很清楚自己想要什么,想成为什么,该怎么做,如何做。但我无法打败自己,所以迄今为止我还是我;

                                                                ——

相关内容

热门资讯

法国阳光依娜减肥效果怎么样 法国阳光依娜减肥效果怎么样做了十天,瘦了三斤,这三斤还是晚上不能吃东西瘦下来的,我感觉没用。很好,做...
亡灵故事 场景一:杰西家2(大... 亡灵故事 场景一:杰西家2(大屋里) 茶杯里面的针要在哪里找磁铁拿出来针是下一个故事要用的道具,找完...
天台山八大景点 天台山八大景点天台山风景区景点如下:1、华顶:台山主峰华顶,海拔1138米,是看日出的好地方。石梁是...
请推荐一些关于秦淮八艳的不错的... 请推荐一些关于秦淮八艳的不错的小说有没有谁能推荐几篇关于秦淮八艳得不错的小说(有关于顾横波得更好)谢...
这是乐山哪儿 这是乐山哪儿 应该是凤凰小区那一截,(平羌路)
幸运钥匙剧情? 幸运钥匙剧情?讲述了成功率100%的职业杀手因为洗澡堂钥匙和无名演员交换身份的故事
创业培训班申请表怎么填写,创业...   了解实现IT灵活性和构建弹性企业的最佳解决方案。      日前,“00后职校女学生自学低码月薪...
强对流+暴雨+大雾三预警 多地... 中央气象台6月8日06时发布强对流天气蓝色预警、暴雨黄色预警、大雾黄色预警,部分地区将有雷暴大风或冰...
长沙应届毕业生补贴 长沙应届毕...   首付每月5000元2000包品牌,税,保险,捷途X70版带回家。      首付每月5000元2...
投资小店面小的项目有哪些,无需...   寿司店这无疑是最适合女生的迎合,前期不需要太多的资金投入,但如果你想把某个年代、某辆摩托车这样的...
手工产品 手工产品 手工产品                     春天不仅是农忙季节,也是台安县新阳工艺美术有限公司负责人严家...
古文观止为什么没有选辑诸子百家... 古文观止为什么没有选辑诸子百家的篇章呢?古文观止里面为什么没有选编《孟子》,《荀子》,《庄子》等等诸...
打通成果转化“最后一公里” 低... 转自:千龙网昨天(7日),2025低空技术与工程大会在北京延庆区开幕。开幕式上,北京理工大学、国彩研...
广西科技大学创业协会,广西科技...   @全区科技型中小企业和创新创业团队,2021年广西科技创新券开始申领!      2021年3月...
小票根撬动文旅新消费 以票根为媒介激活消费潜力,不仅得益于区域演出市场的繁荣,更折射出全国消费升级需求在特定场景下的集中迸...
赛尔号的好多人都起名4399,... 赛尔号的好多人都起名4399,7k7k什么的我一定还玩问★道 真要是玩起问★道来,你会很疯狂的439...
长春南关区天气,南关铁路桥 长...         冬春交替,乍一看还是冷的。最近几天,我市气温有些回升,空气湿度加大,让人担心会出现南...
为什么现在人都怕喝白酒 为什么...   为什么有的人喝白酒,说辣就难以下咽';有的人喝白酒,却意味着回味甘甜醇厚。有人怀疑这可能与酒精度...
沙盘活动目的 沙盘活动目的 沙...   什么是沙盘模拟?      沙盘模拟课程是围绕培训主题,通过带领学员进入竞争激烈的市场环境,进行...
鸣人对战佩恩是多少集到多少集? 鸣人对战佩恩是多少集到多少集?如题,,,,,知道的说下,,,,381至383集,379是卡卡西之死,...